From d73904ff1f0eb9297d2502dd365e5e54346102e2 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Mon, 12 May 2025 18:30:20 +0900 Subject: [PATCH] wip --- packages/frontend/src/components/MkDrive.vue | 1 - .../frontend/src/components/MkModalWindow.vue | 13 +- .../frontend/src/components/MkPostForm.vue | 1 - .../src/components/MkUploadDialog.vue | 151 +++++++++++------- .../admin/custom-emojis-manager.register.vue | 1 - .../frontend/src/pages/chat/room.form.vue | 1 - packages/frontend/src/utility/select-file.ts | 3 +- 7 files changed, 103 insertions(+), 68 deletions(-) diff --git a/packages/frontend/src/components/MkDrive.vue b/packages/frontend/src/components/MkDrive.vue index 036ce1c807..4da77d4ee5 100644 --- a/packages/frontend/src/components/MkDrive.vue +++ b/packages/frontend/src/components/MkDrive.vue @@ -111,7 +111,6 @@ import * as os from '@/os.js'; import { misskeyApi } from '@/utility/misskey-api.js'; import { useStream } from '@/stream.js'; import { i18n } from '@/i18n.js'; -import { uploadFile, uploa______ds } from '@/utility/upload.js'; import { claimAchievement } from '@/utility/achievements.js'; import { prefer } from '@/preferences.js'; import { chooseFileFromPc } from '@/utility/select-file.js'; diff --git a/packages/frontend/src/components/MkModalWindow.vue b/packages/frontend/src/components/MkModalWindow.vue index fb62e9e0cb..6b81e353e6 100644 --- a/packages/frontend/src/components/MkModalWindow.vue +++ b/packages/frontend/src/components/MkModalWindow.vue @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
@@ -125,15 +125,14 @@ defineExpose({ .body { flex: 1; overflow: auto; - background: var(--MI_THEME-panel); + background: var(--MI_THEME-bg); container-type: size; } .footer { - display: flex; - flex-shrink: 0; - background: var(--MI_THEME-windowHeader); - -webkit-backdrop-filter: var(--MI-blur, blur(15px)); - backdrop-filter: var(--MI-blur, blur(15px)); + padding: 8px 16px; + overflow: auto; + background: var(--MI_THEME-bg); + border-top: 1px solid var(--MI_THEME-divider); } diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 5114e98494..705b61f80e 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -127,7 +127,6 @@ import { i18n } from '@/i18n.js'; import { instance } from '@/instance.js'; import { ensureSignin, notesCount, incNotesCount } from '@/i.js'; import { getAccounts, openAccountMenu as openAccountMenu_ } from '@/accounts.js'; -import { uploadFile } from '@/utility/upload.js'; import { deepClone } from '@/utility/clone.js'; import MkRippleEffect from '@/components/MkRippleEffect.vue'; import { miLocalStorage } from '@/local-storage.js'; diff --git a/packages/frontend/src/components/MkUploadDialog.vue b/packages/frontend/src/components/MkUploadDialog.vue index c8a48e8a3c..085ad57000 100644 --- a/packages/frontend/src/components/MkUploadDialog.vue +++ b/packages/frontend/src/components/MkUploadDialog.vue @@ -8,34 +8,44 @@ SPDX-License-Identifier: AGPL-3.0-only ref="dialog" :width="800" :height="500" - @click="cancel()" @close="cancel()" @closed="emit('closed')" > -
-
-
-
-
-

{{ ctx.name }}

-

- {{ i18n.ts.waiting }} - {{ String(Math.floor(ctx.progressValue / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}KB / {{ String(Math.floor(ctx.progressMax / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}KB - {{ Math.floor((ctx.progressValue / ctx.progressMax) * 100) }} -

+
+ + + +
+
+
+
+ +
+
+
+
{{ ctx.name }}
+
+ {{ bytes(ctx.file.size) }} +
+
+
+
+
+ + +
-
@@ -46,13 +56,18 @@ import { markRaw, onMounted, ref, useTemplateRef } from 'vue'; import * as Misskey from 'misskey-js'; import { v4 as uuid } from 'uuid'; import { readAndCompressImage } from '@misskey-dev/browser-image-resizer'; +import { apiUrl } from '@@/js/config.js'; import { getCompressionConfig } from '@/utility/upload/compress-config.js'; import MkModalWindow from '@/components/MkModalWindow.vue'; import { i18n } from '@/i18n.js'; import { prefer } from '@/preferences.js'; -import { $i } from '@/i.js'; +import { ensureSignin } from '@/i.js'; import { instance } from '@/instance.js'; import MkButton from '@/components/MkButton.vue'; +import bytes from '@/filters/bytes.js'; +import MkSwitch from '@/components/MkSwitch.vue'; + +const $i = ensureSignin(); const mimeTypeMap = { 'image/webp': 'webp', @@ -78,12 +93,15 @@ const items = ref([] as { progressMax: number | null; progressValue: number | null; thumbnail: string; + uploading: boolean; uploaded: Misskey.entities.DriveFile | null; file: File; }[]); const dialog = useTemplateRef('dialog'); +const compress = ref(true); + function cancel() { // TODO: アップロードを中止しますか? dialog.value?.close(); @@ -91,52 +109,51 @@ function cancel() { function upload() { for (const item of items.value) { - if ((file.size > instance.maxFileSize) || (file.size > ($i.policies.maxFileSizeMb * 1024 * 1024))) { + if ((item.file.size > instance.maxFileSize) || (item.file.size > ($i.policies.maxFileSizeMb * 1024 * 1024))) { alert({ type: 'error', title: i18n.ts.failedToUpload, text: i18n.ts.cannotUploadBecauseExceedsFileSizeLimit, }); - return Promise.reject(); + continue; } const reader = new FileReader(); reader.onload = async (): Promise => { - const config = !keepOriginal ? await getCompressionConfig(file) : undefined; + const config = compress.value ? await getCompressionConfig(item.file) : undefined; let resizedImage: Blob | undefined; if (config) { try { - const resized = await readAndCompressImage(file, config); - if (resized.size < file.size || file.type === 'image/webp') { + const resized = await readAndCompressImage(item.file, config); + if (resized.size < item.file.size || item.file.type === 'image/webp') { // The compression may not always reduce the file size // (and WebP is not browser safe yet) resizedImage = resized; } if (_DEV_) { - const saved = ((1 - resized.size / file.size) * 100).toFixed(2); - console.log(`Image compression: before ${file.size} bytes, after ${resized.size} bytes, saved ${saved}%`); + const saved = ((1 - resized.size / item.file.size) * 100).toFixed(2); + console.log(`Image compression: before ${item.file.size} bytes, after ${resized.size} bytes, saved ${saved}%`); } - ctx.name = file.type !== config.mimeType ? `${ctx.name}.${mimeTypeMap[config.mimeType]}` : ctx.name; + item.name = item.file.type !== config.mimeType ? `${item.name}.${mimeTypeMap[config.mimeType]}` : item.name; } catch (err) { console.error('Failed to resize image', err); } } const formData = new FormData(); - formData.append('i', $i!.token); + formData.append('i', $i.token); formData.append('force', 'true'); - formData.append('file', resizedImage ?? file); - formData.append('name', ctx.name); - if (_folder) formData.append('folderId', _folder); + formData.append('file', resizedImage ?? item.file); + formData.append('name', item.name); + if (props.folderId) formData.append('folderId', props.folderId); const xhr = new XMLHttpRequest(); xhr.open('POST', apiUrl + '/drive/files/create', true); xhr.onload = ((ev: ProgressEvent) => { - if (xhr.status !== 200 || ev.target == null || ev.target.response == null) { - // TODO: 消すのではなくて(ネットワーク的なエラーなら)再送できるようにしたい - uploa______ds.value = uploa______ds.value.filter(x => x.id !== id); + item.uploading = false; + if (xhr.status !== 200 || ev.target == null || ev.target.response == null) { if (xhr.status === 413) { alert({ type: 'error', @@ -177,22 +194,19 @@ function upload() { } const driveFile = JSON.parse(ev.target.response); - - resolve(driveFile); - - uploa______ds.value = uploa______ds.value.filter(x => x.id !== id); + item.uploaded = driveFile; }) as (ev: ProgressEvent) => any; xhr.upload.onprogress = ev => { if (ev.lengthComputable) { - ctx.progressMax = ev.total; - ctx.progressValue = ev.loaded; + item.progressMax = ev.total; + item.progressValue = ev.loaded; } }; xhr.send(formData); }; - reader.readAsArrayBuffer(file); + reader.readAsArrayBuffer(item.file); } } @@ -215,23 +229,50 @@ onMounted(() => { diff --git a/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue b/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue index e8e944df32..0f4912ece1 100644 --- a/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue +++ b/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue @@ -95,7 +95,6 @@ import MkButton from '@/components/MkButton.vue'; import * as os from '@/os.js'; import { validators } from '@/components/grid/cell-validators.js'; import { chooseFileFromDrive, chooseFileFromPc } from '@/utility/select-file.js'; -import { uploadFile } from '@/utility/upload.js'; import { extractDroppedItems, flattenDroppedFiles } from '@/utility/file-drop.js'; import XRegisterLogs from '@/pages/admin/custom-emojis-manager.logs.vue'; import { copyGridDataToClipboard } from '@/components/grid/grid-utils.js'; diff --git a/packages/frontend/src/pages/chat/room.form.vue b/packages/frontend/src/pages/chat/room.form.vue index 9389b16ce7..f13b91c283 100644 --- a/packages/frontend/src/pages/chat/room.form.vue +++ b/packages/frontend/src/pages/chat/room.form.vue @@ -41,7 +41,6 @@ import { formatTimeString } from '@/utility/format-time-string.js'; import { selectFile } from '@/utility/select-file.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; -import { uploadFile } from '@/utility/upload.js'; import { miLocalStorage } from '@/local-storage.js'; import { misskeyApi } from '@/utility/misskey-api.js'; import { prefer } from '@/preferences.js'; diff --git a/packages/frontend/src/utility/select-file.ts b/packages/frontend/src/utility/select-file.ts index 1d9fa8d3c3..fe8a87f111 100644 --- a/packages/frontend/src/utility/select-file.ts +++ b/packages/frontend/src/utility/select-file.ts @@ -9,7 +9,6 @@ import * as os from '@/os.js'; import { misskeyApi } from '@/utility/misskey-api.js'; import { useStream } from '@/stream.js'; import { i18n } from '@/i18n.js'; -import { uploadFile } from '@/utility/upload.js'; import { prefer } from '@/preferences.js'; export function chooseFileFromPc( @@ -31,7 +30,7 @@ export function chooseFileFromPc( const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUploadDialog.vue')), { files: markRaw(Array.from(input.files)), - uploadFolder, + folderId: uploadFolder, }, { done: driveFiles => { res(driveFiles);