send multiple files at once
This commit is contained in:
parent
6cd47a88c0
commit
31a1eaf3db
1 changed files with 146 additions and 111 deletions
|
|
@ -186,26 +186,38 @@
|
|||
</v-container>
|
||||
|
||||
<input ref="attachment" type="file" name="attachment" @change="handlePickedAttachment($event)"
|
||||
accept="image/*, audio/*, video/*, .pdf" class="d-none" />
|
||||
accept="image/*, audio/*, video/*, .pdf" class="d-none" multiple/>
|
||||
|
||||
<div v-if="currentImageInputPath">
|
||||
<v-dialog v-model="currentImageInputPath" class="ma-0 pa-0" :width="$vuetify.breakpoint.smAndUp ? '50%' : '85%'">
|
||||
<div v-if="isCurrentImageInputsPathDialog">
|
||||
<v-dialog v-model="isCurrentImageInputsPathDialog" class="ma-0 pa-0" :width="$vuetify.breakpoint.smAndUp ? '50%' : '85%'" persistent scrollable>
|
||||
<v-card class="ma-0 pa-0">
|
||||
<v-card-text class="ma-0 pa-2">
|
||||
<v-img v-if="currentImageInput && currentImageInput.image" :aspect-ratio="1" :src="currentImageInput.image"
|
||||
contain class="current-image-input-path" />
|
||||
<div>
|
||||
file: {{ currentImageInputPath.name }}
|
||||
<span v-if="currentImageInput && currentImageInput.scaled && currentImageInput.useScaled">
|
||||
{{ currentImageInput.scaledDimensions.width }} x {{ currentImageInput.scaledDimensions.height }}</span>
|
||||
<span v-else-if="currentImageInput && currentImageInput.dimensions">
|
||||
{{ currentImageInput.dimensions.width }} x {{ currentImageInput.dimensions.height }}</span>
|
||||
<span v-if="currentImageInput && currentImageInput.scaled && currentImageInput.useScaled">
|
||||
({{ formatBytes(currentImageInput.scaledSize) }})</span>
|
||||
<span v-else> ({{ formatBytes(currentImageInputPath.size) }})</span>
|
||||
<v-switch v-if="currentImageInput && currentImageInput.scaled" :label="$t('message.scale_image')"
|
||||
v-model="currentImageInput.useScaled" />
|
||||
</div>
|
||||
<template v-if="Array.isArray(currentImageInputs)">
|
||||
<v-card-text :class="{'ma-0 pa-2' : true, 'd-flex flex-wrap justify-center': currentImageInputs.length > 1}">
|
||||
<div :class="{'col-4': currentImageInputs.length > 1}" v-for="(currentImageInput, id) in currentImageInputs" :key="id">
|
||||
<v-img v-if="currentImageInput && currentImageInput.image" :aspect-ratio="1" :src="currentImageInput.image"
|
||||
contain class="current-image-input-path" />
|
||||
<div>
|
||||
<span v-if="currentImageInput && currentImageInput.scaled && currentImageInput.useScaled">
|
||||
{{ currentImageInput.scaledDimensions.width }} x {{ currentImageInput.scaledDimensions.height }}</span>
|
||||
<span v-else-if="currentImageInput && currentImageInput.dimensions">
|
||||
{{ currentImageInput.dimensions.width }} x {{ currentImageInput.dimensions.height }}</span>
|
||||
<span v-if="currentImageInput && currentImageInput.scaled && currentImageInput.useScaled">
|
||||
({{ formatBytes(currentImageInput.scaledSize) }})</span>
|
||||
<v-switch v-if="currentImageInput && currentImageInput.scaled" :label="$t('message.scale_image')"
|
||||
v-model="currentImageInput.useScaled" />
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-card-text>
|
||||
<div v-for="(currentImageInputPath, id) in currentImageInputsPath" :key="id">
|
||||
<span>file: {{ currentImageInputPath.name }}</span>
|
||||
<span> ({{ formatBytes(currentImageInputPath.size) }})</span>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</template>
|
||||
<v-card-text>
|
||||
<div v-if="currentSendError">{{ currentSendError }}</div>
|
||||
<div v-else>{{ currentSendProgress }}</div>
|
||||
</v-card-text>
|
||||
|
|
@ -338,8 +350,8 @@ export default {
|
|||
timelineWindowPaginating: false,
|
||||
|
||||
scrollPosition: null,
|
||||
currentImageInput: null,
|
||||
currentImageInputPath: null,
|
||||
currentImageInputs: null,
|
||||
currentImageInputsPath: null,
|
||||
currentSendOperation: null,
|
||||
currentSendProgress: null,
|
||||
currentSendShowSendButton: true,
|
||||
|
|
@ -423,6 +435,17 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
isCurrentImageInputsPath() {
|
||||
return Array.isArray(this.currentImageInputsPath)
|
||||
},
|
||||
isCurrentImageInputsPathDialog: {
|
||||
get() {
|
||||
return this.isCurrentImageInputsPath
|
||||
},
|
||||
set() {
|
||||
this.currentImageInputsPath = null
|
||||
}
|
||||
},
|
||||
chatContainer() {
|
||||
const container = this.$refs.chatContainer;
|
||||
if (this.useVoiceMode) {
|
||||
|
|
@ -896,67 +919,73 @@ export default {
|
|||
this.$refs.attachment.click();
|
||||
},
|
||||
|
||||
optimizeImage(e,event,file) {
|
||||
let currentImageInput = {
|
||||
image: e.target.result,
|
||||
dimensions: null,
|
||||
};
|
||||
try {
|
||||
currentImageInput.dimensions = sizeOf(dataUriToBuffer(e.target.result));
|
||||
|
||||
// Need to resize?
|
||||
const w = currentImageInput.dimensions.width;
|
||||
const h = currentImageInput.dimensions.height;
|
||||
if (w > 640 || h > 640) {
|
||||
var aspect = w / h;
|
||||
var newWidth = parseInt((w > h ? 640 : 640 * aspect).toFixed());
|
||||
var newHeight = parseInt((w > h ? 640 / aspect : 640).toFixed());
|
||||
var imageResize = new ImageResize({
|
||||
format: "png",
|
||||
width: newWidth,
|
||||
height: newHeight,
|
||||
outputType: "blob",
|
||||
});
|
||||
imageResize
|
||||
.play(event.target)
|
||||
.then((img) => {
|
||||
Vue.set(
|
||||
currentImageInput,
|
||||
"scaled",
|
||||
new File([img], file.name, {
|
||||
type: img.type,
|
||||
lastModified: Date.now(),
|
||||
})
|
||||
);
|
||||
Vue.set(currentImageInput, "useScaled", true);
|
||||
Vue.set(currentImageInput, "scaledSize", img.size);
|
||||
Vue.set(currentImageInput, "scaledDimensions", {
|
||||
width: newWidth,
|
||||
height: newHeight,
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Resize failed:", err);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to get image dimensions: " + error);
|
||||
}
|
||||
return currentImageInput
|
||||
},
|
||||
handleFileReader(event, file) {
|
||||
if (file) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
this.currentSendShowSendButton = true;
|
||||
if (file.type.startsWith("image/")) {
|
||||
const currentImageInput = this.optimizeImage(e, event, file)
|
||||
this.currentImageInputs = Array.isArray(this.currentImageInputs) ? [...this.currentImageInputs, currentImageInput] : [currentImageInput]
|
||||
}
|
||||
this.currentImageInputsPath = Array.isArray(this.currentImageInputsPath) ? [...this.currentImageInputsPath, file] : [file];
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Handle picked attachment
|
||||
*/
|
||||
handlePickedAttachment(event) {
|
||||
if (event.target.files && event.target.files[0]) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const file = event.target.files[0];
|
||||
this.currentSendShowSendButton = true;
|
||||
if (file.type.startsWith("image/")) {
|
||||
this.currentImageInput = {
|
||||
image: e.target.result,
|
||||
dimensions: null,
|
||||
};
|
||||
try {
|
||||
this.currentImageInput.dimensions = sizeOf(dataUriToBuffer(e.target.result));
|
||||
|
||||
// Need to resize?
|
||||
const w = this.currentImageInput.dimensions.width;
|
||||
const h = this.currentImageInput.dimensions.height;
|
||||
if (w > 640 || h > 640) {
|
||||
var aspect = w / h;
|
||||
var newWidth = parseInt((w > h ? 640 : 640 * aspect).toFixed());
|
||||
var newHeight = parseInt((w > h ? 640 / aspect : 640).toFixed());
|
||||
var imageResize = new ImageResize({
|
||||
format: "png",
|
||||
width: newWidth,
|
||||
height: newHeight,
|
||||
outputType: "blob",
|
||||
});
|
||||
imageResize
|
||||
.play(event.target)
|
||||
.then((img) => {
|
||||
Vue.set(
|
||||
this.currentImageInput,
|
||||
"scaled",
|
||||
new File([img], file.name, {
|
||||
type: img.type,
|
||||
lastModified: Date.now(),
|
||||
})
|
||||
);
|
||||
Vue.set(this.currentImageInput, "useScaled", true);
|
||||
Vue.set(this.currentImageInput, "scaledSize", img.size);
|
||||
Vue.set(this.currentImageInput, "scaledDimensions", {
|
||||
width: newWidth,
|
||||
height: newHeight,
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Resize failed:", err);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to get image dimensions: " + error);
|
||||
}
|
||||
}
|
||||
console.log(this.currentImageInput);
|
||||
this.currentImageInputPath = file;
|
||||
};
|
||||
reader.readAsDataURL(event.target.files[0]);
|
||||
}
|
||||
Object.values(event.target.files).forEach(file => this.handleFileReader(event, file));
|
||||
},
|
||||
|
||||
showStickerPicker() {
|
||||
|
|
@ -975,41 +1004,43 @@ export default {
|
|||
});
|
||||
}
|
||||
},
|
||||
|
||||
sendImage(withText, inputFile) {
|
||||
this.currentSendProgress = null;
|
||||
this.currentSendOperation = util.sendImage(
|
||||
this.$matrix.matrixClient,
|
||||
this.roomId,
|
||||
inputFile,
|
||||
this.onUploadProgress
|
||||
);
|
||||
this.currentSendOperation
|
||||
.then(() => {
|
||||
this.currentSendOperation = null;
|
||||
this.currentImageInputs = null;
|
||||
this.currentImageInputsPath = null;
|
||||
this.currentSendProgress = null;
|
||||
if (withText) {
|
||||
this.sendMessage(withText);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err instanceof AbortError || err === "Abort") {
|
||||
this.currentSendError = null;
|
||||
} else {
|
||||
this.currentSendError = err.LocaleString();
|
||||
}
|
||||
this.currentSendOperation = null;
|
||||
this.currentSendProgress = null;
|
||||
});
|
||||
},
|
||||
sendAttachment(withText) {
|
||||
this.$refs.attachment.value = null;
|
||||
if (this.currentImageInputPath) {
|
||||
var inputFile = this.currentImageInputPath;
|
||||
if (this.currentImageInput && this.currentImageInput.scaled && this.currentImageInput.useScaled) {
|
||||
if (this.isCurrentImageInputsPath) {
|
||||
let inputFiles = this.currentImageInputsPath;
|
||||
if (Array.isArray(this.currentImageInputs) && this.currentImageInputs.scaled && this.currentImageInputs.useScaled) {
|
||||
// Send scaled version of image instead!
|
||||
inputFile = this.currentImageInput.scaled;
|
||||
inputFiles = this.currentImageInputs.map(({scaled}) => scaled)
|
||||
}
|
||||
this.currentSendProgress = null;
|
||||
this.currentSendOperation = util.sendImage(
|
||||
this.$matrix.matrixClient,
|
||||
this.roomId,
|
||||
inputFile,
|
||||
this.onUploadProgress
|
||||
);
|
||||
this.currentSendOperation
|
||||
.then(() => {
|
||||
this.currentSendOperation = null;
|
||||
this.currentImageInput = null;
|
||||
this.currentImageInputPath = null;
|
||||
this.currentSendProgress = null;
|
||||
if (withText) {
|
||||
this.sendMessage(withText);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err instanceof AbortError || err === "Abort") {
|
||||
this.currentSendError = null;
|
||||
} else {
|
||||
this.currentSendError = err.LocaleString();
|
||||
}
|
||||
this.currentSendOperation = null;
|
||||
this.currentSendProgress = null;
|
||||
});
|
||||
inputFiles.forEach((inputFile) => this.sendImage(withText, inputFile))
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -1019,8 +1050,8 @@ export default {
|
|||
this.currentSendOperation.abort();
|
||||
}
|
||||
this.currentSendOperation = null;
|
||||
this.currentImageInput = null;
|
||||
this.currentImageInputPath = null;
|
||||
this.currentImageInputs = null;
|
||||
this.currentImageInputsPath = null;
|
||||
this.currentSendProgress = null;
|
||||
this.currentSendError = null;
|
||||
},
|
||||
|
|
@ -1399,8 +1430,12 @@ export default {
|
|||
},
|
||||
|
||||
onVoiceRecording(event) {
|
||||
console.log('voice..')
|
||||
console.log(event)
|
||||
console.log(event.file)
|
||||
this.currentSendShowSendButton = false;
|
||||
this.currentImageInputPath = event.file;
|
||||
//this.currentImageInputsPath = event.file;
|
||||
this.currentImageInputsPath = Array.isArray(this.currentImageInputsPath) ? [...this.currentImageInputsPath, event.file] : [event.file];
|
||||
var text = undefined;
|
||||
if (this.currentInput && this.currentInput.length > 0) {
|
||||
text = this.currentInput;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue