mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-05-24 16:14:11 +02:00
Feat: ドライブ周りのUIの強化 (#16011)
* wip * wip * Update MkDrive.vue * wip * Update MkDrive.vue * Update MkDrive.vue * wip * Update MkDrive.vue * Update MkDrive.vue * wip * Update MkDrive.vue * wip * wip * wip * wip * Update MkDrive.vue * wip * wip * wip * wip * wip * wip * wip * feat(frontend): upload dialog (#16032) * wip * wip * Update MkUploadDialog.vue * wip * wip * wip * wip * wip * Update MkUploadDialog.vue * wip * wip * Update MkDrive.vue * wip * wip * Update MkPostForm.vue * wip * Update room.form.vue * Update os.ts * wiop * wip * wip * wip * wip * wip * wip * wip * Update select-file.ts * wip * wip * Update MkDrive.vue * Update drag-and-drop.ts * wip * wip * wop * wip * wip * Update MkDrive.vue * Update CHANGELOG.md * wipo * Update MkDrive.folder.vue * wip * Update MkUploaderDialog.vue * wip * wip * Update MkUploaderDialog.vue * wip * Update MkDrive.vue * Update MkDrive.vue * wip * wip
This commit is contained in:
@@ -87,7 +87,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||
import { validators } from '@/components/grid/cell-validators.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import MkPagingButtons from '@/components/MkPagingButtons.vue';
|
||||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { selectFile } from '@/utility/drive.js';
|
||||
import { copyGridDataToClipboard, removeDataFromGrid } from '@/components/grid/grid-utils.js';
|
||||
import { useLoading } from '@/composables/use-loading.js';
|
||||
|
||||
|
||||
@@ -35,20 +35,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<XRegisterLogs :logs="requestLogs"/>
|
||||
</MkFolder>
|
||||
|
||||
<div
|
||||
:class="[$style.uploadBox, [isDragOver ? $style.dragOver : {}]]"
|
||||
@dragover.prevent="isDragOver = true"
|
||||
@dragleave.prevent="isDragOver = false"
|
||||
@drop.prevent.stop="onDrop"
|
||||
>
|
||||
<div style="margin-top: 1em">
|
||||
{{ i18n.ts._customEmojisManager._local._register.emojiInputAreaCaption }}
|
||||
</div>
|
||||
<ul>
|
||||
<li>{{ i18n.ts._customEmojisManager._local._register.emojiInputAreaList1 }}</li>
|
||||
<li><a @click.prevent="onFileSelectClicked">{{ i18n.ts._customEmojisManager._local._register.emojiInputAreaList2 }}</a></li>
|
||||
<li><a @click.prevent="onDriveSelectClicked">{{ i18n.ts._customEmojisManager._local._register.emojiInputAreaList3 }}</a></li>
|
||||
</ul>
|
||||
<div class="_buttonsCenter">
|
||||
<MkButton primary rounded @click="onFileSelectClicked">{{ i18n.ts.uplaod }}</MkButton>
|
||||
<MkButton primary rounded @click="onDriveSelectClicked">{{ i18n.ts.fromDrive }}</MkButton>
|
||||
</div>
|
||||
|
||||
<div v-if="gridItems.length > 0" :class="$style.gridArea">
|
||||
@@ -94,8 +83,7 @@ import MkFolder from '@/components/MkFolder.vue';
|
||||
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 { chooseDriveFile, chooseFileFromPcAndUpload } from '@/utility/drive.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';
|
||||
@@ -311,75 +299,21 @@ async function onClearClicked() {
|
||||
}
|
||||
}
|
||||
|
||||
async function onDrop(ev: DragEvent) {
|
||||
isDragOver.value = false;
|
||||
|
||||
const droppedFiles = await extractDroppedItems(ev).then(it => flattenDroppedFiles(it));
|
||||
const confirm = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.tsx._customEmojisManager._local._register.confirmUploadEmojisDescription({ count: droppedFiles.length }),
|
||||
});
|
||||
if (confirm.canceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uploadedItems = Array.of<{ droppedFile: DroppedFile, driveFile: Misskey.entities.DriveFile }>();
|
||||
try {
|
||||
uploadedItems.push(
|
||||
...await os.promiseDialog(
|
||||
Promise.all(
|
||||
droppedFiles.map(async (it) => ({
|
||||
droppedFile: it,
|
||||
driveFile: await uploadFile(
|
||||
it.file,
|
||||
selectedFolderId.value,
|
||||
it.file.name.replace(/\.[^.]+$/, ''),
|
||||
true,
|
||||
),
|
||||
}),
|
||||
),
|
||||
),
|
||||
() => {
|
||||
},
|
||||
() => {
|
||||
},
|
||||
),
|
||||
);
|
||||
} catch (err) {
|
||||
// ダイアログは共通部品側で出ているはずなので何もしない
|
||||
return;
|
||||
}
|
||||
|
||||
const items = uploadedItems.map(({ droppedFile, driveFile }) => {
|
||||
const item = fromDriveFile(driveFile);
|
||||
if (directoryToCategory.value) {
|
||||
item.category = droppedFile.path
|
||||
.replace(/^\//, '')
|
||||
.replace(/\/[^/]+$/, '')
|
||||
.replace(droppedFile.file.name, '');
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
gridItems.value.push(...items);
|
||||
}
|
||||
|
||||
async function onFileSelectClicked() {
|
||||
const driveFiles = await chooseFileFromPc(
|
||||
true,
|
||||
{
|
||||
uploadFolder: selectedFolderId.value,
|
||||
keepOriginal: true,
|
||||
// 拡張子は消す
|
||||
nameConverter: (file) => file.name.replace(/\.[a-zA-Z0-9]+$/, ''),
|
||||
},
|
||||
);
|
||||
const driveFiles = await chooseFileFromPcAndUpload({
|
||||
multiple: true,
|
||||
folderId: selectedFolderId.value,
|
||||
// 拡張子は消す
|
||||
nameConverter: (file) => file.name.replace(/\.[a-zA-Z0-9]+$/, ''),
|
||||
});
|
||||
|
||||
gridItems.value.push(...driveFiles.map(fromDriveFile));
|
||||
}
|
||||
|
||||
async function onDriveSelectClicked() {
|
||||
const driveFiles = await chooseFileFromDrive(true);
|
||||
const driveFiles = await chooseDriveFile({
|
||||
multiple: true,
|
||||
});
|
||||
gridItems.value.push(...driveFiles.map(fromDriveFile));
|
||||
}
|
||||
|
||||
@@ -436,23 +370,6 @@ onMounted(async () => {
|
||||
background-color: var(--MI_THEME-infoWarnBg);
|
||||
}
|
||||
|
||||
.uploadBox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border: 0.5px dotted var(--MI_THEME-accentedBg);
|
||||
border-radius: var(--MI-radius);
|
||||
background-color: var(--MI_THEME-accentedBg);
|
||||
box-sizing: border-box;
|
||||
|
||||
&.dragOver {
|
||||
cursor: copy;
|
||||
}
|
||||
}
|
||||
|
||||
.gridArea {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
|
||||
@@ -73,7 +73,7 @@ import * as Misskey from 'misskey-js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkColorInput from '@/components/MkColorInput.vue';
|
||||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { selectFile } from '@/utility/drive.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { definePage } from '@/page.js';
|
||||
|
||||
@@ -38,15 +38,15 @@ import { onMounted, watch, ref, shallowRef, computed, nextTick, readonly, onBefo
|
||||
import * as Misskey from 'misskey-js';
|
||||
//import insertTextAtCursor from 'insert-text-at-cursor';
|
||||
import { formatTimeString } from '@/utility/format-time-string.js';
|
||||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { selectFile } from '@/utility/drive.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';
|
||||
import { Autocomplete } from '@/utility/autocomplete.js';
|
||||
import { emojiPicker } from '@/utility/emoji-picker.js';
|
||||
import { checkDragDataType, getDragData } from '@/drag-and-drop.js';
|
||||
|
||||
const props = defineProps<{
|
||||
user?: Misskey.entities.UserDetailed | null;
|
||||
@@ -84,8 +84,11 @@ async function onPaste(ev: ClipboardEvent) {
|
||||
if (!pastedFile) return;
|
||||
const lio = pastedFile.name.lastIndexOf('.');
|
||||
const ext = lio >= 0 ? pastedFile.name.slice(lio) : '';
|
||||
const formatted = formatTimeString(new Date(pastedFile.lastModified), pastedFileName).replace(/{{number}}/g, '1') + ext;
|
||||
if (formatted) upload(pastedFile, formatted);
|
||||
const formattedName = formatTimeString(new Date(pastedFile.lastModified), pastedFileName).replace(/{{number}}/g, '1') + ext;
|
||||
const renamedFile = new File([pastedFile], formattedName, { type: pastedFile.type });
|
||||
os.launchUploader([renamedFile], { multiple: false }).then(driveFiles => {
|
||||
file.value = driveFiles[0];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (items[0].kind === 'file') {
|
||||
@@ -101,8 +104,7 @@ function onDragover(ev: DragEvent) {
|
||||
if (!ev.dataTransfer) return;
|
||||
|
||||
const isFile = ev.dataTransfer.items[0].kind === 'file';
|
||||
const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
|
||||
if (isFile || isDriveFile) {
|
||||
if (isFile || checkDragDataType(ev, ['driveFiles'])) {
|
||||
ev.preventDefault();
|
||||
switch (ev.dataTransfer.effectAllowed) {
|
||||
case 'all':
|
||||
@@ -129,7 +131,7 @@ function onDrop(ev: DragEvent): void {
|
||||
// ファイルだったら
|
||||
if (ev.dataTransfer.files.length === 1) {
|
||||
ev.preventDefault();
|
||||
upload(ev.dataTransfer.files[0]);
|
||||
os.launchUploader([Array.from(ev.dataTransfer.files)[0]], { multiple: false });
|
||||
return;
|
||||
} else if (ev.dataTransfer.files.length > 1) {
|
||||
ev.preventDefault();
|
||||
@@ -141,10 +143,12 @@ function onDrop(ev: DragEvent): void {
|
||||
}
|
||||
|
||||
//#region ドライブのファイル
|
||||
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
||||
if (driveFile != null && driveFile !== '') {
|
||||
file.value = JSON.parse(driveFile);
|
||||
ev.preventDefault();
|
||||
{
|
||||
const droppedData = getDragData(ev, 'driveFiles');
|
||||
if (droppedData != null) {
|
||||
file.value = droppedData[0];
|
||||
ev.preventDefault();
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
@@ -172,13 +176,11 @@ function chooseFile(ev: MouseEvent) {
|
||||
function onChangeFile() {
|
||||
if (fileEl.value == null || fileEl.value.files == null) return;
|
||||
|
||||
if (fileEl.value.files[0]) upload(fileEl.value.files[0]);
|
||||
}
|
||||
|
||||
function upload(fileToUpload: File, name?: string) {
|
||||
uploadFile(fileToUpload, prefer.s.uploadFolder, name).then(res => {
|
||||
file.value = res;
|
||||
});
|
||||
if (fileEl.value.files[0]) {
|
||||
os.launchUploader(Array.from(fileEl.value.files), { multiple: false }).then(driveFiles => {
|
||||
file.value = driveFiles[0];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function send() {
|
||||
|
||||
@@ -78,7 +78,7 @@ import MkPagination from '@/components/MkPagination.vue';
|
||||
import MkRemoteEmojiEditDialog from '@/components/MkRemoteEmojiEditDialog.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import FormSplit from '@/components/form/split.vue';
|
||||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { selectFile } from '@/utility/drive.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { getProxiedImageUrl } from '@/utility/media-proxy.js';
|
||||
|
||||
@@ -23,6 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkSystemIcon v-if="iconType === 'success'" type="success" style="width: 150px;"/>
|
||||
<MkSystemIcon v-if="iconType === 'warn'" type="warn" style="width: 150px;"/>
|
||||
<MkSystemIcon v-if="iconType === 'error'" type="error" style="width: 150px;"/>
|
||||
<MkSystemIcon v-if="iconType === 'waiting'" type="waiting" style="width: 150px;"/>
|
||||
<MkSelect
|
||||
v-model="iconType" :items="[
|
||||
{ label: 'info', value: 'info' },
|
||||
@@ -30,6 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
{ label: 'success', value: 'success' },
|
||||
{ label: 'warn', value: 'warn' },
|
||||
{ label: 'error', value: 'error' },
|
||||
{ label: 'waiting', value: 'waiting' },
|
||||
]"
|
||||
></MkSelect>
|
||||
|
||||
|
||||
@@ -20,9 +20,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<button v-tooltip="i18n.ts.createNoteFromTheFile" class="_button" :class="$style.fileQuickActionsOthersButton" @click="postThis()">
|
||||
<i class="ti ti-pencil"></i>
|
||||
</button>
|
||||
<button v-if="isImage" v-tooltip="i18n.ts.cropImage" class="_button" :class="$style.fileQuickActionsOthersButton" @click="crop()">
|
||||
<i class="ti ti-crop"></i>
|
||||
</button>
|
||||
<button v-if="file.isSensitive" v-tooltip="i18n.ts.unmarkAsSensitive" class="_button" :class="$style.fileQuickActionsOthersButton" @click="toggleSensitive()">
|
||||
<i class="ti ti-eye"></i>
|
||||
</button>
|
||||
@@ -83,6 +80,8 @@ import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { useRouter } from '@/router.js';
|
||||
import { selectDriveFolder } from '@/utility/drive.js';
|
||||
import { globalEvents } from '@/events.js';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@@ -127,19 +126,10 @@ function postThis() {
|
||||
});
|
||||
}
|
||||
|
||||
function crop() {
|
||||
if (!file.value) return;
|
||||
|
||||
os.cropImage(file.value, {
|
||||
aspectRatio: NaN,
|
||||
uploadFolder: file.value.folderId ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
function move() {
|
||||
if (!file.value) return;
|
||||
|
||||
os.selectDriveFolder(false).then(folder => {
|
||||
selectDriveFolder(null).then(folder => {
|
||||
misskeyApi('drive/files/update', {
|
||||
fileId: file.value.id,
|
||||
folderId: folder[0] ? folder[0].id : null,
|
||||
@@ -210,12 +200,14 @@ async function deleteFile() {
|
||||
type: 'warning',
|
||||
text: i18n.tsx.driveFileDeleteConfirm({ name: file.value.name }),
|
||||
});
|
||||
|
||||
if (canceled) return;
|
||||
|
||||
await os.apiWithDialog('drive/files/delete', {
|
||||
fileId: file.value.id,
|
||||
});
|
||||
|
||||
globalEvents.emit('driveFilesDeleted', [file.value]);
|
||||
|
||||
router.push('/my/drive');
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<XDrive @cd="x => folder = x"/>
|
||||
<MkDrive @cd="x => folder = x"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import XDrive from '@/components/MkDrive.vue';
|
||||
import MkDrive from '@/components/MkDrive.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { customEmojiCategories } from '@/custom-emojis.js';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { selectFile } from '@/utility/drive.js';
|
||||
import MkRolePreview from '@/components/MkRolePreview.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -44,7 +44,7 @@ import MkInput from '@/components/MkInput.vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import FormSuspense from '@/components/form/suspense.vue';
|
||||
import { selectFiles } from '@/utility/select-file.js';
|
||||
import { selectFiles } from '@/utility/drive.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { definePage } from '@/page.js';
|
||||
|
||||
@@ -20,14 +20,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
|
||||
import { onMounted, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { chooseDriveFile } from '@/utility/drive.js';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: Misskey.entities.PageBlock & { type: 'image' };
|
||||
@@ -41,7 +41,7 @@ const emit = defineEmits<{
|
||||
const file = ref<Misskey.entities.DriveFile | null>(null);
|
||||
|
||||
async function choose() {
|
||||
os.selectDriveFile(false).then((fileResponse) => {
|
||||
chooseDriveFile({ multiple: false }).then((fileResponse) => {
|
||||
file.value = fileResponse[0];
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
|
||||
@@ -71,7 +71,7 @@ import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { selectFile } from '@/utility/drive.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
@@ -164,7 +164,7 @@ import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { selectFile } from '@/utility/drive.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { $i } from '@/i.js';
|
||||
|
||||
@@ -98,7 +98,7 @@ import { definePage } from '@/page.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue';
|
||||
import { reloadAsk } from '@/utility/reload-ask.js';
|
||||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { selectFile } from '@/utility/drive.js';
|
||||
|
||||
const navWindow = prefer.model('deck.navWindow');
|
||||
const useSimpleUiForNonRootPages = prefer.model('deck.useSimpleUiForNonRootPages');
|
||||
|
||||
@@ -99,6 +99,7 @@ import { ensureSignin } from '@/i.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue';
|
||||
import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
|
||||
import { selectDriveFolder } from '@/utility/drive.js';
|
||||
|
||||
const $i = ensureSignin();
|
||||
|
||||
@@ -138,7 +139,7 @@ if (prefer.s.uploadFolder) {
|
||||
}
|
||||
|
||||
function chooseUploadFolder() {
|
||||
os.selectDriveFolder(false).then(async folder => {
|
||||
selectDriveFolder(null).then(async folder => {
|
||||
prefer.commit('uploadFolder', folder[0] ? folder[0].id : null);
|
||||
os.success();
|
||||
if (prefer.s.uploadFolder) {
|
||||
|
||||
@@ -161,7 +161,7 @@ import MkSelect from '@/components/MkSelect.vue';
|
||||
import FormSplit from '@/components/form/split.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import FormSlot from '@/components/form/slot.vue';
|
||||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { chooseDriveFile } from '@/utility/drive.js';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { ensureSignin } from '@/i.js';
|
||||
@@ -257,54 +257,100 @@ function save() {
|
||||
}
|
||||
|
||||
function changeAvatar(ev) {
|
||||
selectFile(ev.currentTarget ?? ev.target, i18n.ts.avatar).then(async (file) => {
|
||||
let originalOrCropped = file;
|
||||
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'question',
|
||||
text: i18n.ts.cropImageAsk,
|
||||
okText: i18n.ts.cropYes,
|
||||
cancelText: i18n.ts.cropNo,
|
||||
});
|
||||
|
||||
if (!canceled) {
|
||||
originalOrCropped = await os.cropImage(file, {
|
||||
aspectRatio: 1,
|
||||
});
|
||||
}
|
||||
|
||||
async function done(driveFile) {
|
||||
const i = await os.apiWithDialog('i/update', {
|
||||
avatarId: originalOrCropped.id,
|
||||
avatarId: driveFile.id,
|
||||
});
|
||||
$i.avatarId = i.avatarId;
|
||||
$i.avatarUrl = i.avatarUrl;
|
||||
claimAchievement('profileFilled');
|
||||
});
|
||||
}
|
||||
|
||||
os.popupMenu([{
|
||||
text: i18n.ts.avatar,
|
||||
type: 'label',
|
||||
}, {
|
||||
text: i18n.ts.upload,
|
||||
icon: 'ti ti-upload',
|
||||
action: async () => {
|
||||
const files = await os.chooseFileFromPc({ multiple: false });
|
||||
const file = files[0];
|
||||
|
||||
let originalOrCropped = file;
|
||||
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'question',
|
||||
text: i18n.ts.cropImageAsk,
|
||||
okText: i18n.ts.cropYes,
|
||||
cancelText: i18n.ts.cropNo,
|
||||
});
|
||||
|
||||
if (!canceled) {
|
||||
originalOrCropped = await os.cropImageFile(file, {
|
||||
aspectRatio: 1,
|
||||
});
|
||||
}
|
||||
|
||||
const driveFile = (await os.launchUploader([originalOrCropped], { multiple: false }))[0];
|
||||
done(driveFile);
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.fromDrive,
|
||||
icon: 'ti ti-cloud',
|
||||
action: () => {
|
||||
chooseDriveFile({ multiple: false }).then(files => {
|
||||
done(files[0]);
|
||||
});
|
||||
},
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
function changeBanner(ev) {
|
||||
selectFile(ev.currentTarget ?? ev.target, i18n.ts.banner).then(async (file) => {
|
||||
let originalOrCropped = file;
|
||||
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'question',
|
||||
text: i18n.ts.cropImageAsk,
|
||||
okText: i18n.ts.cropYes,
|
||||
cancelText: i18n.ts.cropNo,
|
||||
});
|
||||
|
||||
if (!canceled) {
|
||||
originalOrCropped = await os.cropImage(file, {
|
||||
aspectRatio: 2,
|
||||
});
|
||||
}
|
||||
|
||||
async function done(driveFile) {
|
||||
const i = await os.apiWithDialog('i/update', {
|
||||
bannerId: originalOrCropped.id,
|
||||
bannerId: driveFile.id,
|
||||
});
|
||||
$i.bannerId = i.bannerId;
|
||||
$i.bannerUrl = i.bannerUrl;
|
||||
});
|
||||
}
|
||||
|
||||
os.popupMenu([{
|
||||
text: i18n.ts.banner,
|
||||
type: 'label',
|
||||
}, {
|
||||
text: i18n.ts.upload,
|
||||
icon: 'ti ti-upload',
|
||||
action: async () => {
|
||||
const files = await os.chooseFileFromPc({ multiple: false });
|
||||
const file = files[0];
|
||||
|
||||
let originalOrCropped = file;
|
||||
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'question',
|
||||
text: i18n.ts.cropImageAsk,
|
||||
okText: i18n.ts.cropYes,
|
||||
cancelText: i18n.ts.cropNo,
|
||||
});
|
||||
|
||||
if (!canceled) {
|
||||
originalOrCropped = await os.cropImageFile(file, {
|
||||
aspectRatio: 2,
|
||||
});
|
||||
}
|
||||
|
||||
const driveFile = (await os.launchUploader([originalOrCropped], { multiple: false }))[0];
|
||||
done(driveFile);
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.fromDrive,
|
||||
icon: 'ti ti-cloud',
|
||||
action: () => {
|
||||
chooseDriveFile({ multiple: false }).then(files => {
|
||||
done(files[0]);
|
||||
});
|
||||
},
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
@@ -40,7 +40,7 @@ import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { playMisskeySfxFile, soundsTypes, getSoundDuration } from '@/utility/sound.js';
|
||||
import { selectFile } from '@/utility/select-file.js';
|
||||
import { selectFile } from '@/utility/drive.js';
|
||||
|
||||
const props = defineProps<{
|
||||
type: SoundType;
|
||||
|
||||
Reference in New Issue
Block a user