mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-25 09:43:49 +02:00
* refactor: dialogs * fix: storeAvatarImage * FriendLog.vue * FriendLog.vue * FriendLog.vue * GameLog.vue * fix: next day button jumping to the wrong date * sync master * fix: launchGame * Notification.vue * Feed.vue * Search.vue * Profile.vue * PlayerList.vue * Login.vue * utils * update dialog * del gameLog.pug * fix * fix: group role cannot be displayed currently * fix: "Hide Friends in Same Instance" hides players in unrelated private instances (#1210) * fix * fix: "Hide Friends in Same Instance" does not work when "Split Favorite Friends" is enabled * fix Notification.vue message * fix: deleteFavoriteNoConfirm * fix: feed status style * fix: infinite loading when deleting note * fix: private players will not be hidden when 'Hide Friends in Same Instance', and 'Hide Friends in Same Instance' will not work when 'Split Favorite Friends'
1025 lines
40 KiB
Vue
1025 lines
40 KiB
Vue
<template>
|
|
<safe-dialog
|
|
class="x-dialog"
|
|
:visible="galleryDialogVisible"
|
|
:title="t('dialog.gallery_icons.header')"
|
|
width="97vw"
|
|
top="5vh"
|
|
append-to-body
|
|
@close="closeGalleryDialog">
|
|
<el-tabs type="card" ref="galleryTabs">
|
|
<el-tab-pane v-loading="galleryDialogGalleryLoading">
|
|
<span slot="label">
|
|
{{ t('dialog.gallery_icons.gallery') }}
|
|
<span style="color: #909399; font-size: 12px; margin-left: 5px">
|
|
{{ galleryTable.length }}/64
|
|
</span>
|
|
</span>
|
|
<input
|
|
id="GalleryUploadButton"
|
|
type="file"
|
|
accept="image/*"
|
|
@change="onFileChangeGallery"
|
|
style="display: none" />
|
|
<span>{{ t('dialog.gallery_icons.recommended_image_size') }}: 1200x900px (4:3)</span>
|
|
<br />
|
|
<br />
|
|
<el-button-group>
|
|
<el-button type="default" size="small" @click="refreshGalleryTable" icon="el-icon-refresh">
|
|
{{ t('dialog.gallery_icons.refresh') }}
|
|
</el-button>
|
|
<el-button
|
|
type="default"
|
|
size="small"
|
|
@click="displayGalleryUpload"
|
|
icon="el-icon-upload2"
|
|
:disabled="!API.currentUser.$isVRCPlus">
|
|
{{ t('dialog.gallery_icons.upload') }}
|
|
</el-button>
|
|
<el-button
|
|
type="default"
|
|
size="small"
|
|
@click="setProfilePicOverride('')"
|
|
icon="el-icon-close"
|
|
:disabled="!API.currentUser.profilePicOverride">
|
|
{{ t('dialog.gallery_icons.clear') }}
|
|
</el-button>
|
|
</el-button-group>
|
|
<br />
|
|
<div
|
|
class="x-friend-item"
|
|
v-if="image.versions && image.versions.length > 0"
|
|
v-for="image in galleryTable"
|
|
:key="image.id"
|
|
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
|
|
<div
|
|
class="vrcplus-icon"
|
|
v-if="image.versions[image.versions.length - 1].file.url"
|
|
@click="setProfilePicOverride(image.id)"
|
|
:class="{ 'current-vrcplus-icon': compareCurrentProfilePic(image.id) }">
|
|
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
|
|
</div>
|
|
<div style="float: right; margin-top: 5px">
|
|
<el-button
|
|
type="default"
|
|
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)"
|
|
size="mini"
|
|
icon="el-icon-picture-outline"
|
|
circle></el-button>
|
|
<el-button
|
|
type="default"
|
|
@click="deleteGalleryImage(image.id)"
|
|
size="mini"
|
|
icon="el-icon-delete"
|
|
circle
|
|
style="margin-left: 5px"></el-button>
|
|
</div>
|
|
</div>
|
|
</el-tab-pane>
|
|
|
|
<el-tab-pane v-loading="galleryDialogIconsLoading" lazy>
|
|
<span slot="label">
|
|
{{ t('dialog.gallery_icons.icons') }}
|
|
<span style="color: #909399; font-size: 12px; margin-left: 5px">
|
|
{{ VRCPlusIconsTable.length }}/64
|
|
</span>
|
|
</span>
|
|
<input
|
|
id="VRCPlusIconUploadButton"
|
|
type="file"
|
|
accept="image/*"
|
|
@change="onFileChangeVRCPlusIcon"
|
|
style="display: none" />
|
|
<span>{{ t('dialog.gallery_icons.recommended_image_size') }}: 2048x2048px (1:1)</span>
|
|
<br />
|
|
<br />
|
|
<el-button-group>
|
|
<el-button type="default" size="small" @click="refreshVRCPlusIconsTable" icon="el-icon-refresh">
|
|
{{ t('dialog.gallery_icons.refresh') }}
|
|
</el-button>
|
|
<el-button
|
|
type="default"
|
|
size="small"
|
|
@click="displayVRCPlusIconUpload"
|
|
icon="el-icon-upload2"
|
|
:disabled="!API.currentUser.$isVRCPlus">
|
|
{{ t('dialog.gallery_icons.upload') }}
|
|
</el-button>
|
|
<el-button
|
|
type="default"
|
|
size="small"
|
|
@click="setVRCPlusIcon('')"
|
|
icon="el-icon-close"
|
|
:disabled="!API.currentUser.userIcon">
|
|
{{ t('dialog.gallery_icons.clear') }}
|
|
</el-button>
|
|
</el-button-group>
|
|
<br />
|
|
<div
|
|
class="x-friend-item"
|
|
v-if="image.versions && image.versions.length > 0"
|
|
v-for="image in VRCPlusIconsTable"
|
|
:key="image.id"
|
|
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
|
|
<div
|
|
class="vrcplus-icon"
|
|
v-if="image.versions[image.versions.length - 1].file.url"
|
|
@click="setVRCPlusIcon(image.id)"
|
|
:class="{ 'current-vrcplus-icon': compareCurrentVRCPlusIcon(image.id) }">
|
|
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
|
|
</div>
|
|
<div style="float: right; margin-top: 5px">
|
|
<el-button
|
|
type="default"
|
|
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)"
|
|
size="mini"
|
|
icon="el-icon-picture-outline"
|
|
circle></el-button>
|
|
<el-button
|
|
type="default"
|
|
@click="deleteVRCPlusIcon(image.id)"
|
|
size="mini"
|
|
icon="el-icon-delete"
|
|
circle
|
|
style="margin-left: 5px"></el-button>
|
|
</div>
|
|
</div>
|
|
</el-tab-pane>
|
|
|
|
<el-tab-pane v-loading="galleryDialogEmojisLoading" lazy>
|
|
<span slot="label">
|
|
{{ t('dialog.gallery_icons.emojis') }}
|
|
<span style="color: #909399; font-size: 12px; margin-left: 5px"> {{ emojiTable.length }}/9 </span>
|
|
</span>
|
|
<input
|
|
id="EmojiUploadButton"
|
|
type="file"
|
|
accept="image/*"
|
|
@change="onFileChangeEmoji"
|
|
style="display: none" />
|
|
<span>{{ t('dialog.gallery_icons.recommended_image_size') }}: 1024x1024px (1:1)</span>
|
|
<br />
|
|
<br />
|
|
<div style="display: flex; align-items: center">
|
|
<el-button-group style="margin-right: 10px">
|
|
<el-button type="default" size="small" @click="refreshEmojiTable" icon="el-icon-refresh">
|
|
{{ t('dialog.gallery_icons.refresh') }}
|
|
</el-button>
|
|
<el-button
|
|
type="default"
|
|
size="small"
|
|
@click="displayEmojiUpload"
|
|
icon="el-icon-upload2"
|
|
:disabled="!API.currentUser.$isVRCPlus">
|
|
{{ t('dialog.gallery_icons.upload') }}
|
|
</el-button>
|
|
</el-button-group>
|
|
<el-select v-model="emojiAnimationStyle" popper-class="max-height-el-select">
|
|
<el-option-group>
|
|
{{ t('dialog.gallery_icons.emoji_animation_styles') }}
|
|
<el-option
|
|
class="x-friend-item"
|
|
v-for="(fileName, styleName) in emojiAnimationStyleList"
|
|
:key="styleName"
|
|
:label="styleName"
|
|
:value="styleName"
|
|
style="height: auto">
|
|
<div class="avatar" style="width: 200px; height: 200px">
|
|
<img v-lazy="`${emojiAnimationStyleUrl}${fileName}`" />
|
|
</div>
|
|
<div class="detail">
|
|
<span class="name" v-text="styleName" style="margin-right: 100px"></span>
|
|
</div>
|
|
</el-option>
|
|
</el-option-group>
|
|
</el-select>
|
|
<el-checkbox v-model="emojiAnimType" style="margin-left: 10px; margin-right: 10px">
|
|
<span>{{ t('dialog.gallery_icons.emoji_animation_type') }}</span>
|
|
</el-checkbox>
|
|
<template v-if="emojiAnimType">
|
|
<span style="margin-right: 10px">{{ t('dialog.gallery_icons.emoji_animation_fps') }}</span>
|
|
<el-input-number
|
|
size="small"
|
|
v-model="emojiAnimFps"
|
|
:min="1"
|
|
:max="64"
|
|
style="margin-right: 10px; width: 112px"></el-input-number>
|
|
<span style="margin-right: 10px">{{
|
|
t('dialog.gallery_icons.emoji_animation_frame_count')
|
|
}}</span>
|
|
<el-input-number
|
|
size="small"
|
|
v-model="emojiAnimFrameCount"
|
|
:min="2"
|
|
:max="64"
|
|
style="margin-right: 10px; width: 112px"></el-input-number>
|
|
<el-checkbox v-model="emojiAnimLoopPingPong" style="margin-left: 10px; margin-right: 10px">
|
|
<span>{{ t('dialog.gallery_icons.emoji_loop_pingpong') }}</span>
|
|
</el-checkbox>
|
|
<br />
|
|
<br />
|
|
<span>{{ t('dialog.gallery_icons.flipbook_info') }}</span>
|
|
</template>
|
|
</div>
|
|
<br />
|
|
<div
|
|
class="x-friend-item"
|
|
v-if="image.versions && image.versions.length > 0"
|
|
v-for="image in emojiTable"
|
|
:key="image.id"
|
|
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
|
|
<div
|
|
class="vrcplus-icon"
|
|
v-if="image.versions[image.versions.length - 1].file.url"
|
|
style="overflow: hidden"
|
|
@click="
|
|
showFullscreenImageDialog(
|
|
image.versions[image.versions.length - 1].file.url,
|
|
getEmojiFileName(image)
|
|
)
|
|
">
|
|
<template v-if="image.frames">
|
|
<div
|
|
class="avatar"
|
|
:style="
|
|
generateEmojiStyle(
|
|
image.versions[image.versions.length - 1].file.url,
|
|
image.framesOverTime,
|
|
image.frames,
|
|
image.loopStyle
|
|
)
|
|
"></div>
|
|
</template>
|
|
<template v-else>
|
|
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
|
|
</template>
|
|
</div>
|
|
<div style="display: inline-block; margin: 5px">
|
|
<span v-if="image.loopStyle === 'pingpong'">
|
|
<i class="el-icon-refresh el-icon--left"></i>
|
|
</span>
|
|
<span style="margin-right: 5px">{{ image.animationStyle }}</span>
|
|
<span v-if="image.framesOverTime" style="margin-right: 5px">{{ image.framesOverTime }}fps</span>
|
|
<span v-if="image.frames" style="margin-right: 5px">{{ image.frames }}frames</span>
|
|
<br />
|
|
</div>
|
|
<div style="float: right; margin-top: 5px">
|
|
<el-button
|
|
type="default"
|
|
@click="
|
|
showFullscreenImageDialog(
|
|
image.versions[image.versions.length - 1].file.url,
|
|
getEmojiFileName(image)
|
|
)
|
|
"
|
|
size="mini"
|
|
icon="el-icon-picture-outline"
|
|
circle></el-button>
|
|
<el-button
|
|
type="default"
|
|
@click="deleteEmoji(image.id)"
|
|
size="mini"
|
|
icon="el-icon-delete"
|
|
circle
|
|
style="margin-left: 5px"></el-button>
|
|
</div>
|
|
</div>
|
|
</el-tab-pane>
|
|
|
|
<el-tab-pane v-loading="galleryDialogStickersLoading" lazy>
|
|
<span slot="label">
|
|
{{ t('dialog.gallery_icons.stickers') }}
|
|
<span style="color: #909399; font-size: 12px; margin-left: 5px"> {{ stickerTable.length }}/9 </span>
|
|
</span>
|
|
<input
|
|
id="StickerUploadButton"
|
|
type="file"
|
|
accept="image/*"
|
|
@change="onFileChangeSticker"
|
|
style="display: none" />
|
|
<span>{{ t('dialog.gallery_icons.recommended_image_size') }}: 1024x1024px (1:1)</span>
|
|
<br />
|
|
<br />
|
|
<el-button-group>
|
|
<el-button type="default" size="small" @click="refreshStickerTable" icon="el-icon-refresh">
|
|
{{ t('dialog.gallery_icons.refresh') }}
|
|
</el-button>
|
|
<el-button
|
|
type="default"
|
|
size="small"
|
|
@click="displayStickerUpload"
|
|
icon="el-icon-upload2"
|
|
:disabled="!API.currentUser.$isVRCPlus">
|
|
{{ t('dialog.gallery_icons.upload') }}
|
|
</el-button>
|
|
</el-button-group>
|
|
<br />
|
|
<div
|
|
class="x-friend-item"
|
|
v-if="image.versions && image.versions.length > 0"
|
|
v-for="image in stickerTable"
|
|
:key="image.id"
|
|
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
|
|
<div
|
|
class="vrcplus-icon"
|
|
v-if="image.versions[image.versions.length - 1].file.url"
|
|
style="overflow: hidden"
|
|
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)">
|
|
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
|
|
</div>
|
|
<div style="float: right; margin-top: 5px">
|
|
<el-button
|
|
type="default"
|
|
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)"
|
|
size="mini"
|
|
icon="el-icon-picture-outline"
|
|
circle></el-button>
|
|
<el-button
|
|
type="default"
|
|
@click="deleteSticker(image.id)"
|
|
size="mini"
|
|
icon="el-icon-delete"
|
|
circle
|
|
style="margin-left: 5px"></el-button>
|
|
</div>
|
|
</div>
|
|
</el-tab-pane>
|
|
|
|
<el-tab-pane v-loading="galleryDialogPrintsLoading" lazy>
|
|
<span slot="label">
|
|
{{ t('dialog.gallery_icons.prints') }}
|
|
<span style="color: #909399; font-size: 12px; margin-left: 5px"> {{ printTable.length }}/64 </span>
|
|
</span>
|
|
<input
|
|
id="PrintUploadButton"
|
|
type="file"
|
|
accept="image/*"
|
|
@change="onFileChangePrint"
|
|
style="display: none" />
|
|
<span>{{ t('dialog.gallery_icons.recommended_image_size') }}: 1920x1080px (16:9)</span>
|
|
<br />
|
|
<br />
|
|
<div style="display: flex; align-items: center">
|
|
<el-button-group>
|
|
<el-button type="default" size="small" @click="refreshPrintTable" icon="el-icon-refresh">
|
|
{{ t('dialog.gallery_icons.refresh') }}
|
|
</el-button>
|
|
<el-button
|
|
type="default"
|
|
size="small"
|
|
@click="displayPrintUpload"
|
|
icon="el-icon-upload2"
|
|
:disabled="!API.currentUser.$isVRCPlus">
|
|
{{ t('dialog.gallery_icons.upload') }}
|
|
</el-button>
|
|
</el-button-group>
|
|
<el-input
|
|
type="textarea"
|
|
v-model="printUploadNote"
|
|
size="mini"
|
|
rows="1"
|
|
resize="none"
|
|
maxlength="32"
|
|
style="margin-left: 10px; width: 300px"
|
|
:placeholder="t('dialog.gallery_icons.note')"></el-input>
|
|
<el-checkbox v-model="printCropBorder" style="margin-left: 10px; margin-right: 10px">
|
|
<span>{{ t('dialog.gallery_icons.crop_print_border') }}</span>
|
|
</el-checkbox>
|
|
</div>
|
|
<br />
|
|
<div
|
|
class="x-friend-item"
|
|
v-for="image in printTable"
|
|
:key="image.id"
|
|
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
|
|
<div
|
|
class="vrcplus-icon"
|
|
style="overflow: hidden"
|
|
@click="showFullscreenImageDialog(image.files.image, getPrintFileName(image))">
|
|
<img class="avatar" v-lazy="image.files.image" />
|
|
</div>
|
|
<div style="margin-top: 5px; width: 208px">
|
|
<span class="x-ellipsis" v-if="image.note" v-text="image.note" style="display: block"></span>
|
|
<span v-else style="display: block"> </span>
|
|
<location
|
|
class="x-ellipsis"
|
|
v-if="image.worldId"
|
|
:location="image.worldId"
|
|
:hint="image.worldName"
|
|
style="display: block"></location>
|
|
<span v-else style="display: block"> </span>
|
|
<display-name
|
|
class="x-ellipsis"
|
|
v-if="image.authorId"
|
|
:userid="image.authorId"
|
|
:hint="image.authorName"
|
|
style="color: #909399; font-family: monospace; display: block"></display-name>
|
|
<span v-else style="font-family: monospace; display: block"> </span>
|
|
<span
|
|
class="x-ellipsis"
|
|
v-if="image.createdAt"
|
|
style="color: #909399; font-family: monospace; font-size: 11px; display: block">
|
|
{{ image.createdAt | formatDate('long') }}
|
|
</span>
|
|
<span v-else style="display: block"> </span>
|
|
</div>
|
|
<div style="float: right">
|
|
<el-button
|
|
type="default"
|
|
@click="showFullscreenImageDialog(image.files.image, getPrintFileName(image))"
|
|
size="mini"
|
|
icon="el-icon-picture-outline"
|
|
circle></el-button>
|
|
<el-button
|
|
type="default"
|
|
@click="deletePrint(image.id)"
|
|
size="mini"
|
|
icon="el-icon-delete"
|
|
circle
|
|
style="margin-left: 5px"></el-button>
|
|
</div>
|
|
</div>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
</safe-dialog>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { getCurrentInstance, inject, ref } from 'vue';
|
|
import { useI18n } from 'vue-i18n-bridge';
|
|
import { userRequest, vrcPlusIconRequest, vrcPlusImageRequest } from '../../../api';
|
|
import { extractFileId } from '../../../composables/shared/utils';
|
|
import { emojiAnimationStyleList, emojiAnimationStyleUrl } from '../../../composables/user/constants/emoji';
|
|
import { getPrintFileName } from '../../../composables/user/utils';
|
|
import Location from '../../Location.vue';
|
|
|
|
const { t } = useI18n();
|
|
|
|
const { proxy } = getCurrentInstance();
|
|
const { $message } = proxy;
|
|
|
|
const API = inject('API');
|
|
const showFullscreenImageDialog = inject('showFullscreenImageDialog');
|
|
|
|
const props = defineProps({
|
|
galleryDialogVisible: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
galleryDialogGalleryLoading: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
galleryDialogIconsLoading: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
galleryDialogEmojisLoading: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
galleryDialogStickersLoading: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
galleryDialogPrintsLoading: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
galleryTable: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
// eslint-disable-next-line vue/prop-name-casing
|
|
VRCPlusIconsTable: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
emojiTable: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
stickerTable: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
printUploadNote: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
printCropBorder: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
printTable: {
|
|
type: Array,
|
|
required: true
|
|
}
|
|
});
|
|
|
|
const emit = defineEmits([
|
|
'refreshGalleryTable',
|
|
'refreshVRCPlusIconsTable',
|
|
'refreshStickerTable',
|
|
'refreshEmojiTable',
|
|
'refreshPrintTable',
|
|
'closeGalleryDialog'
|
|
]);
|
|
|
|
const emojiAnimFps = ref(15);
|
|
const emojiAnimFrameCount = ref(4);
|
|
const emojiAnimType = ref(false);
|
|
const emojiAnimationStyle = ref('Stop');
|
|
const emojiAnimLoopPingPong = ref(false);
|
|
|
|
function refreshGalleryTable() {
|
|
emit('refreshGalleryTable');
|
|
}
|
|
|
|
function closeGalleryDialog() {
|
|
emit('closeGalleryDialog');
|
|
}
|
|
|
|
function onFileChangeGallery(e) {
|
|
const clearFile = function () {
|
|
if (document.querySelector('#GalleryUploadButton')) {
|
|
document.querySelector('#GalleryUploadButton').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);
|
|
vrcPlusImageRequest.uploadGalleryImage(base64Body).then((args) => {
|
|
$message({
|
|
message: t('message.gallery.uploaded'),
|
|
type: 'success'
|
|
});
|
|
return args;
|
|
});
|
|
};
|
|
r.readAsBinaryString(files[0]);
|
|
clearFile();
|
|
}
|
|
|
|
function displayGalleryUpload() {
|
|
document.getElementById('GalleryUploadButton').click();
|
|
}
|
|
|
|
function setProfilePicOverride(fileId) {
|
|
if (!API.currentUser.$isVRCPlus) {
|
|
$message({
|
|
message: 'VRCPlus required',
|
|
type: 'error'
|
|
});
|
|
return;
|
|
}
|
|
let profilePicOverride = '';
|
|
if (fileId) {
|
|
profilePicOverride = `${API.endpointDomain}/file/${fileId}/1`;
|
|
}
|
|
if (profilePicOverride === API.currentUser.profilePicOverride) {
|
|
return;
|
|
}
|
|
userRequest
|
|
.saveCurrentUser({
|
|
profilePicOverride
|
|
})
|
|
.then((args) => {
|
|
$message({
|
|
message: 'Profile picture changed',
|
|
type: 'success'
|
|
});
|
|
return args;
|
|
});
|
|
}
|
|
|
|
function compareCurrentProfilePic(fileId) {
|
|
const currentProfilePicOverride = extractFileId(API.currentUser.profilePicOverride);
|
|
if (fileId === currentProfilePicOverride) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function deleteGalleryImage(fileId) {
|
|
vrcPlusIconRequest.deleteFile(fileId).then((args) => {
|
|
// API.$emit('GALLERYIMAGE:DELETE', args);
|
|
// API.$on('GALLERYIMAGE:DELETE')
|
|
const array = props.galleryTable;
|
|
const { length } = array;
|
|
for (let i = 0; i < length; ++i) {
|
|
if (args.fileId === array[i].id) {
|
|
array.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return args;
|
|
});
|
|
}
|
|
|
|
function onFileChangeVRCPlusIcon(e) {
|
|
const clearFile = function () {
|
|
if (document.querySelector('#VRCPlusIconUploadButton')) {
|
|
document.querySelector('#VRCPlusIconUploadButton').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);
|
|
vrcPlusIconRequest.uploadVRCPlusIcon(base64Body).then((args) => {
|
|
$message({
|
|
message: t('message.icon.uploaded'),
|
|
type: 'success'
|
|
});
|
|
return args;
|
|
});
|
|
};
|
|
r.readAsBinaryString(files[0]);
|
|
clearFile();
|
|
}
|
|
|
|
function refreshVRCPlusIconsTable() {
|
|
emit('refreshVRCPlusIconsTable');
|
|
}
|
|
|
|
function displayVRCPlusIconUpload() {
|
|
document.getElementById('VRCPlusIconUploadButton').click();
|
|
}
|
|
|
|
function setVRCPlusIcon(fileId) {
|
|
if (!API.currentUser.$isVRCPlus) {
|
|
$message({
|
|
message: 'VRCPlus required',
|
|
type: 'error'
|
|
});
|
|
return;
|
|
}
|
|
let userIcon = '';
|
|
if (fileId) {
|
|
userIcon = `${API.endpointDomain}/file/${fileId}/1`;
|
|
}
|
|
if (userIcon === API.currentUser.userIcon) {
|
|
return;
|
|
}
|
|
userRequest
|
|
.saveCurrentUser({
|
|
userIcon
|
|
})
|
|
.then((args) => {
|
|
$message({
|
|
message: 'Icon changed',
|
|
type: 'success'
|
|
});
|
|
return args;
|
|
});
|
|
}
|
|
|
|
function compareCurrentVRCPlusIcon(userIcon) {
|
|
const currentUserIcon = extractFileId(API.currentUser.userIcon);
|
|
if (userIcon === currentUserIcon) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function deleteVRCPlusIcon(fileId) {
|
|
vrcPlusIconRequest.deleteFile(fileId).then((args) => {
|
|
// API.$emit('VRCPLUSICON:DELETE', args);
|
|
// API.$on('VRCPLUSICON:DELETE')
|
|
const array = props.VRCPlusIconsTable;
|
|
const { length } = array;
|
|
for (let i = 0; i < length; ++i) {
|
|
if (args.fileId === array[i].id) {
|
|
array.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
return args;
|
|
});
|
|
}
|
|
|
|
function parseEmojiFileName(fileName) {
|
|
// remove file extension
|
|
fileName = fileName.replace(/\.[^/.]+$/, '');
|
|
const array = fileName.split('_');
|
|
for (let i = 0; i < array.length; ++i) {
|
|
const value = array[i];
|
|
if (value.endsWith('animationStyle')) {
|
|
emojiAnimType.value = false;
|
|
emojiAnimationStyle.value = value.replace('animationStyle', '').toLowerCase();
|
|
}
|
|
if (value.endsWith('frames')) {
|
|
emojiAnimType.value = true;
|
|
emojiAnimFrameCount.value = parseInt(value.replace('frames', ''));
|
|
}
|
|
if (value.endsWith('fps')) {
|
|
emojiAnimFps.value = parseInt(value.replace('fps', ''));
|
|
}
|
|
if (value.endsWith('loopStyle')) {
|
|
emojiAnimLoopPingPong.value = value === 'pingpong';
|
|
}
|
|
}
|
|
}
|
|
|
|
function onFileChangeEmoji(e) {
|
|
const clearFile = function () {
|
|
if (document.querySelector('#EmojiUploadButton')) {
|
|
document.querySelector('#EmojiUploadButton').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;
|
|
}
|
|
// set Emoji settings from fileName
|
|
parseEmojiFileName(files[0].name);
|
|
const r = new FileReader();
|
|
r.onload = function () {
|
|
const params = {
|
|
tag: emojiAnimType.value ? 'emojianimated' : 'emoji',
|
|
animationStyle: emojiAnimationStyle.value.toLowerCase(),
|
|
maskTag: 'square'
|
|
};
|
|
if (emojiAnimType.value) {
|
|
params.frames = emojiAnimFrameCount.value;
|
|
params.framesOverTime = emojiAnimFps.value;
|
|
}
|
|
if (emojiAnimLoopPingPong.value) {
|
|
params.loopStyle = 'pingpong';
|
|
}
|
|
const base64Body = btoa(r.result);
|
|
vrcPlusImageRequest.uploadEmoji(base64Body, params).then((args) => {
|
|
$message({
|
|
message: t('message.emoji.uploaded'),
|
|
type: 'success'
|
|
});
|
|
return args;
|
|
});
|
|
};
|
|
r.readAsBinaryString(files[0]);
|
|
clearFile();
|
|
}
|
|
|
|
function refreshEmojiTable() {
|
|
emit('refreshEmojiTable');
|
|
}
|
|
|
|
function displayEmojiUpload() {
|
|
document.getElementById('EmojiUploadButton').click();
|
|
}
|
|
|
|
function getEmojiFileName(emoji) {
|
|
if (emoji.frames) {
|
|
const loopStyle = emoji.loopStyle || 'linear';
|
|
return `${emoji.name}_${emoji.animationStyle}animationStyle_${emoji.frames}frames_${emoji.framesOverTime}fps_${loopStyle}loopStyle.png`;
|
|
} else {
|
|
return `${emoji.name}_${emoji.animationStyle}animationStyle.png`;
|
|
}
|
|
}
|
|
|
|
function generateEmojiStyle(url, fps, frameCount, loopStyle) {
|
|
let framesPerLine = 2;
|
|
if (frameCount > 4) framesPerLine = 4;
|
|
if (frameCount > 16) framesPerLine = 8;
|
|
const animationDurationMs = (1000 / fps) * frameCount;
|
|
const frameSize = 1024 / framesPerLine;
|
|
const scale = 100 / (frameSize / 200);
|
|
const animStyle = loopStyle === 'pingpong' ? 'alternate' : 'none';
|
|
const style = `
|
|
transform: scale(${scale / 100});
|
|
transform-origin: top left;
|
|
width: ${frameSize}px;
|
|
height: ${frameSize}px;
|
|
background: url('${url}') 0 0;
|
|
animation: ${animationDurationMs}ms steps(1) 0s infinite ${animStyle} running animated-emoji-${frameCount};
|
|
`;
|
|
return style;
|
|
}
|
|
|
|
function deleteEmoji(fileId) {
|
|
vrcPlusIconRequest.deleteFile(fileId).then((args) => {
|
|
// API.$emit('EMOJI:DELETE', args);
|
|
// API.$on('EMOJI:DELETE')
|
|
const array = props.emojiTable;
|
|
const { length } = array;
|
|
for (let i = 0; i < length; ++i) {
|
|
if (args.fileId === array[i].id) {
|
|
array.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
return args;
|
|
});
|
|
}
|
|
|
|
function onFileChangeSticker(e) {
|
|
const clearFile = function () {
|
|
if (document.querySelector('#StickerUploadButton')) {
|
|
document.querySelector('#StickerUploadButton').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 params = {
|
|
tag: 'sticker',
|
|
maskTag: 'square'
|
|
};
|
|
const base64Body = btoa(r.result);
|
|
vrcPlusImageRequest.uploadSticker(base64Body, params).then((args) => {
|
|
$message({
|
|
message: t('message.sticker.uploaded'),
|
|
type: 'success'
|
|
});
|
|
return args;
|
|
});
|
|
};
|
|
r.readAsBinaryString(files[0]);
|
|
clearFile();
|
|
}
|
|
|
|
function refreshStickerTable() {
|
|
emit('refreshStickerTable');
|
|
}
|
|
|
|
function displayStickerUpload() {
|
|
document.getElementById('StickerUploadButton').click();
|
|
}
|
|
|
|
function deleteSticker(fileId) {
|
|
vrcPlusIconRequest.deleteFile(fileId).then((args) => {
|
|
// API.$emit('STICKER:DELETE', args);
|
|
// API.$on('STICKER:DELETE')
|
|
const array = props.stickerTable;
|
|
const { length } = array;
|
|
for (let i = 0; i < length; ++i) {
|
|
if (args.fileId === array[i].id) {
|
|
array.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return args;
|
|
});
|
|
}
|
|
|
|
function onFileChangePrint(e) {
|
|
const clearFile = function () {
|
|
if (document.querySelector('#PrintUploadButton')) {
|
|
document.querySelector('#PrintUploadButton').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 date = new Date();
|
|
// why the fuck isn't this UTC
|
|
date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
|
|
const timestamp = date.toISOString().slice(0, 19);
|
|
const params = {
|
|
note: props.printUploadNote,
|
|
// worldId: '',
|
|
timestamp
|
|
};
|
|
const base64Body = btoa(r.result);
|
|
const cropWhiteBorder = props.printCropBorder;
|
|
vrcPlusImageRequest.uploadPrint(base64Body, cropWhiteBorder, params).then((args) => {
|
|
$message({
|
|
message: t('message.print.uploaded'),
|
|
type: 'success'
|
|
});
|
|
// API.$on('PRINT:ADD')
|
|
if (Object.keys(props.printTable).length !== 0) {
|
|
props.printTable.unshift(args.json);
|
|
}
|
|
|
|
return args;
|
|
});
|
|
};
|
|
r.readAsBinaryString(files[0]);
|
|
clearFile();
|
|
}
|
|
|
|
function refreshPrintTable() {
|
|
emit('refreshPrintTable');
|
|
}
|
|
|
|
function displayPrintUpload() {
|
|
document.getElementById('PrintUploadButton').click();
|
|
}
|
|
|
|
function deletePrint(printId) {
|
|
vrcPlusImageRequest.deletePrint(printId).then((args) => {
|
|
// API.$on('PRINT:DELETE');
|
|
const array = props.printTable;
|
|
const { length } = array;
|
|
for (let i = 0; i < length; ++i) {
|
|
if (args.printId === array[i].id) {
|
|
array.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
</script>
|