file types and exports
This commit is contained in:
parent
db04080463
commit
324ccd70b3
21 changed files with 339 additions and 55 deletions
14
package-lock.json
generated
14
package-lock.json
generated
|
|
@ -28,7 +28,7 @@
|
|||
"jszip": "^3.9.1",
|
||||
"linkify-html": "^4.1.0",
|
||||
"linkifyjs": "^4.1.0",
|
||||
"material-design-icons-iconfont": "^6.1",
|
||||
"material-design-icons-iconfont": "^6.7.0",
|
||||
"matrix-js-sdk": "^23.4.0",
|
||||
"md-gum-polyfill": "^1.0.0",
|
||||
"mic-recorder-to-mp3": "^2.2.2",
|
||||
|
|
@ -9936,9 +9936,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/material-design-icons-iconfont": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.1.0.tgz",
|
||||
"integrity": "sha512-wRJtOo1v1ch+gN8PRsj0IGJznk+kQ8mz13ds/nuhLI+Qyf/931ZlRpd92oq0IRPpZIb+bhX8pRjzIVdcPDKmiQ=="
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.7.0.tgz",
|
||||
"integrity": "sha512-lSj71DgVv20kO0kGbs42icDzbRot61gEDBLQACzkUuznRQBUYmbxzEkGU6dNBb5fRWHMaScYlAXX96HQ4/cJWA=="
|
||||
},
|
||||
"node_modules/matrix-events-sdk": {
|
||||
"version": "0.0.1",
|
||||
|
|
@ -24023,9 +24023,9 @@
|
|||
}
|
||||
},
|
||||
"material-design-icons-iconfont": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.1.0.tgz",
|
||||
"integrity": "sha512-wRJtOo1v1ch+gN8PRsj0IGJznk+kQ8mz13ds/nuhLI+Qyf/931ZlRpd92oq0IRPpZIb+bhX8pRjzIVdcPDKmiQ=="
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.7.0.tgz",
|
||||
"integrity": "sha512-lSj71DgVv20kO0kGbs42icDzbRot61gEDBLQACzkUuznRQBUYmbxzEkGU6dNBb5fRWHMaScYlAXX96HQ4/cJWA=="
|
||||
},
|
||||
"matrix-events-sdk": {
|
||||
"version": "0.0.1",
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
"jszip": "^3.9.1",
|
||||
"linkify-html": "^4.1.0",
|
||||
"linkifyjs": "^4.1.0",
|
||||
"material-design-icons-iconfont": "^6.1",
|
||||
"material-design-icons-iconfont": "^6.7.0",
|
||||
"matrix-js-sdk": "^23.4.0",
|
||||
"md-gum-polyfill": "^1.0.0",
|
||||
"mic-recorder-to-mp3": "^2.2.2",
|
||||
|
|
|
|||
|
|
@ -783,12 +783,23 @@ body {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.download-text {
|
||||
width: 100%;
|
||||
color: white;
|
||||
}
|
||||
.download-size {
|
||||
font-size: 70%;
|
||||
color: white;
|
||||
}
|
||||
.download-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.room-name,
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@
|
|||
</v-container>
|
||||
|
||||
<input ref="attachment" type="file" name="attachment" @change="handlePickedAttachment($event)"
|
||||
accept="image/*, audio/*, video/*, .pdf, .apk, .ipa, .zip" class="d-none" multiple/>
|
||||
accept="image/*,audio/*,video/*,.pdf,application/pdf,.apk,application/vnd.android.package-archive,.ipa,.zip,application/zip,application/x-zip-compressed,multipart/x-zip" class="d-none" multiple/>
|
||||
|
||||
<div v-if="currentFileInputsDialog && !useFileModeNonAdmin">
|
||||
<v-dialog v-model="currentFileInputsDialog" class="ma-0 pa-0" :width="$vuetify.breakpoint.smAndUp ? '50%' : '85%'" persistent scrollable>
|
||||
|
|
@ -1545,6 +1545,7 @@ export default {
|
|||
},
|
||||
|
||||
download(event) {
|
||||
console.error("DOWNLOAD!!!");
|
||||
if ((event.isThreadRoot || event.isMxThread) && this.timelineSet) {
|
||||
const children = this.timelineSet.relations.getAllChildEventsForEvent(event.getId()).filter(e => util.downloadableTypes().includes(e.getContent().msgtype));
|
||||
children.forEach(child => util.download(this.$matrix.matrixClient, child));
|
||||
|
|
|
|||
|
|
@ -287,6 +287,7 @@ export default {
|
|||
var imageFolder = zip.folder("images");
|
||||
var audioFolder = zip.folder("audio");
|
||||
var videoFolder = zip.folder("video");
|
||||
var filesFolder = zip.folder("files");
|
||||
|
||||
var downloadPromises = [];
|
||||
let components = this.$refs.exportedEvent;
|
||||
|
|
@ -321,7 +322,8 @@ export default {
|
|||
for (let imageIndex = 0; imageIndex < images.length; imageIndex++) {
|
||||
const img = images[imageIndex];
|
||||
img.onerror = undefined;
|
||||
img.src = './avatars/' + fileName;
|
||||
img.removeAttribute("src");
|
||||
img.setAttribute("data-exported-src", './avatars/' + fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -421,13 +423,15 @@ export default {
|
|||
var extension = ".mp3";
|
||||
let fileName = comp.event.getId() + extension;
|
||||
audioFolder.file(fileName, blob); // TODO calc bytes
|
||||
//this.$nextTick(() => {
|
||||
let elements = comp.$el.getElementsByTagName("audio");
|
||||
let element = elements && elements[0];
|
||||
if (element) {
|
||||
element.src = "./audio/" + fileName;
|
||||
element.setAttribute("data-exported-src", "./audio/" + fileName);
|
||||
}
|
||||
this.processedEvents += 1;
|
||||
resolve(true);
|
||||
//});
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
@ -449,13 +453,36 @@ export default {
|
|||
var extension = ".mp4";
|
||||
let fileName = comp.event.getId() + extension;
|
||||
videoFolder.file(fileName, blob); // TODO calc bytes
|
||||
// comp.src = "./video/" + fileName;
|
||||
let elements = comp.$el.getElementsByTagName("video");
|
||||
let element = elements && elements[0];
|
||||
if (element) {
|
||||
element.src = "./video/" + fileName;
|
||||
element.setAttribute("data-exported-src", "./video/" + fileName);
|
||||
}
|
||||
this.processedEvents += 1;
|
||||
|
||||
resolve(true);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((ignoredErr) => {
|
||||
this.processedEvents += 1;
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "MessageIncomingFileExport":
|
||||
case "MessageOutgoingFileExport":
|
||||
downloadPromises.push(
|
||||
util
|
||||
.getAttachment(this.$matrix.matrixClient, comp.event, null, true)
|
||||
.then((blob) => {
|
||||
if (currentMediaSize + blob.size <= maxMediaSize) {
|
||||
currentMediaSize += blob.size;
|
||||
return new Promise((resolve, ignoredReject) => {
|
||||
var extension = util.getFileExtension(comp.event);
|
||||
let fileName = comp.event.getId() + extension;
|
||||
filesFolder.file(fileName, blob);
|
||||
comp.href="./files/" + fileName;
|
||||
this.processedEvents += 1;
|
||||
resolve(true);
|
||||
});
|
||||
}
|
||||
|
|
@ -504,7 +531,8 @@ export default {
|
|||
getCssRules(root);
|
||||
|
||||
this.$nextTick(() => {
|
||||
doc += this.$refs.exportRoot.outerHTML;
|
||||
const contentHtml = this.$refs.exportRoot.outerHTML;
|
||||
doc += contentHtml.replaceAll("data-exported-src=", "src=");
|
||||
doc += "</div></body></html>";
|
||||
|
||||
zip.file("chat.html", doc);
|
||||
|
|
|
|||
|
|
@ -19,10 +19,12 @@ import MessageIncomingImageExport from "./messages/export/MessageIncomingImageEx
|
|||
import MessageIncomingAudioExport from "./messages/export/MessageIncomingAudioExport";
|
||||
import MessageIncomingVideoExport from "./messages/export/MessageIncomingVideoExport";
|
||||
import MessageIncomingThreadExport from "./messages/export/MessageIncomingThreadExport";
|
||||
import MessageIncomingFileExport from "./messages/export/MessageIncomingFileExport";
|
||||
import MessageOutgoingImageExport from "./messages/export/MessageOutgoingImageExport";
|
||||
import MessageOutgoingAudioExport from "./messages/export/MessageOutgoingAudioExport";
|
||||
import MessageOutgoingVideoExport from "./messages/export/MessageOutgoingVideoExport";
|
||||
import MessageOutgoingThreadExport from "./messages/export/MessageOutgoingThreadExport";
|
||||
import MessageOutgoingFileExport from "./messages/export/MessageOutgoingFileExport";
|
||||
import ContactJoin from "./messages/ContactJoin.vue";
|
||||
import ContactLeave from "./messages/ContactLeave.vue";
|
||||
import ContactInvited from "./messages/ContactInvited.vue";
|
||||
|
|
@ -172,6 +174,9 @@ export default {
|
|||
event.getContent().info.mimetype &&
|
||||
event.getContent().info.mimetype.startsWith("image/svg")
|
||||
) {
|
||||
if (isForExport) {
|
||||
return MessageIncomingFileExport;
|
||||
}
|
||||
return MessageIncomingFile;
|
||||
}
|
||||
if (isForExport) {
|
||||
|
|
@ -189,6 +194,9 @@ export default {
|
|||
}
|
||||
return MessageIncomingVideo;
|
||||
} else if (event.getContent().msgtype == "m.file") {
|
||||
if (isForExport) {
|
||||
return MessageIncomingFileExport;
|
||||
}
|
||||
return MessageIncomingFile;
|
||||
} else if (stickers.isStickerShortcode(event.getContent().body)) {
|
||||
return MessageIncomingSticker;
|
||||
|
|
@ -223,6 +231,9 @@ export default {
|
|||
}
|
||||
return MessageOutgoingVideo;
|
||||
} else if (event.getContent().msgtype == "m.file") {
|
||||
if (isForExport) {
|
||||
return MessageOutgoingFileExport;
|
||||
}
|
||||
return MessageOutgoingFile;
|
||||
} else if (stickers.isStickerShortcode(event.getContent().body)) {
|
||||
return MessageOutgoingSticker;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,22 @@
|
|||
<template>
|
||||
<v-responsive v-if="item.event.getContent().msgtype == 'm.video'" :class="{'thumbnail-item': true, 'preview': previewOnly}"
|
||||
<v-responsive v-if="item.event.getContent().msgtype == 'm.video' && item.src" :class="{'thumbnail-item': true, 'preview': previewOnly}"
|
||||
@click.stop="$emit('itemclick', {item: item})">
|
||||
<video :src="item.src" :controls="!previewOnly" class="w-100 h-100">
|
||||
{{ $t('fallbacks.video_file') }}
|
||||
</video>
|
||||
</v-responsive>
|
||||
<v-img v-else-if="item.event.getContent().msgtype == 'm.image'" :aspect-ratio="previewOnly ? (16 / 9) : undefined" :class="{'thumbnail-item': true, 'preview': previewOnly}" :src="item.src" :contain="!previewOnly" :cover="previewOnly"
|
||||
<v-img v-else-if="item.event.getContent().msgtype == 'm.image' && item.src" :aspect-ratio="previewOnly ? (16 / 9) : undefined" :class="{'thumbnail-item': true, 'preview': previewOnly}" :src="item.src" :contain="!previewOnly" :cover="previewOnly"
|
||||
@click.stop="$emit('itemclick', {item: item})" />
|
||||
<div v-else :class="{'thumbnail-item': true, 'preview': previewOnly, 'file-item': true}" @click.stop="$emit('itemclick', {item: item})">
|
||||
<v-icon>description</v-icon>
|
||||
{{ $sanitize(item.event.getContent().body) }}
|
||||
<v-icon>{{ fileTypeIcon }}</v-icon>
|
||||
<b>{{ $sanitize(fileName) }}</b>
|
||||
<div>{{ fileSize }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
import util from "../../plugins/utils";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
/**
|
||||
|
|
@ -32,6 +35,26 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
fileTypeIcon() {
|
||||
if (util.isFileTypeAPK(this.item.event)) {
|
||||
return "phone_android";
|
||||
} else if (util.isFileTypeIPA(this.item.event)) {
|
||||
return "phone_iphone";
|
||||
} else if (util.isFileTypePDF(this.item.event)) {
|
||||
return "picture_as_pdf";
|
||||
} else if (util.isFileTypeZip(this.item.event)) {
|
||||
return "folder_zip";
|
||||
}
|
||||
return "description"
|
||||
},
|
||||
fileName() {
|
||||
return util.getFileName(this.item.event);
|
||||
},
|
||||
fileSize() {
|
||||
return util.getFileSizeFormatted(this.item.event);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,7 @@
|
|||
</div>
|
||||
|
||||
<div class="message">
|
||||
<span>{{ $t('message.file_prefix') }}</span>
|
||||
<span
|
||||
class="cursor-pointer"
|
||||
@click.stop="$emit('download')"
|
||||
v-html="linkify($sanitize(messageText))"
|
||||
/>
|
||||
<ThumbnailView class="clickable" v-on:itemclick="$emit('download')" :item="{ event: event, src: null }" />
|
||||
<span class="edit-marker" v-if="event.replacingEventId()"
|
||||
>{{ $t('message.edited') }}</span
|
||||
>
|
||||
|
|
@ -25,11 +20,12 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import ThumbnailView from '../file_mode/ThumbnailView.vue';
|
||||
import MessageIncoming from "./MessageIncoming.vue";
|
||||
|
||||
export default {
|
||||
extends: MessageIncoming,
|
||||
components: { MessageIncoming }
|
||||
components: { MessageIncoming, ThumbnailView }
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,15 @@
|
|||
{{ $t('message.download_progress',{percentage: downloadProgress}) }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="userInitiatedDownloadsOnly && !src" class="download-overlay">
|
||||
<div class="text-center download-text">
|
||||
{{ fileName }}
|
||||
</div>
|
||||
<div class="text-center download-size">
|
||||
{{ fileSize }}
|
||||
</div>
|
||||
<v-icon size="32" color="white" class="clickable" @click="loadAttachmentSource(event, true)">download</v-icon>
|
||||
</div>
|
||||
</v-responsive>
|
||||
</div>
|
||||
</message-incoming>
|
||||
|
|
|
|||
|
|
@ -11,12 +11,7 @@
|
|||
|
||||
|
||||
<div class="message">
|
||||
<span>{{ $t('message.file_prefix') }}</span>
|
||||
<span
|
||||
class="cursor-pointer"
|
||||
@click.stop="$emit('download')"
|
||||
v-html="linkify($sanitize(messageText))"
|
||||
/>
|
||||
<ThumbnailView class="clickable" v-on:itemclick="$emit('download')" :item="{ event: event, src: null }" />
|
||||
<span class="edit-marker" v-if="event.replacingEventId()"
|
||||
>{{ $t('message.edited') }}</span
|
||||
>
|
||||
|
|
@ -26,11 +21,12 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import ThumbnailView from '../file_mode/ThumbnailView.vue';
|
||||
import MessageOutgoing from "./MessageOutgoing.vue";
|
||||
|
||||
export default {
|
||||
extends: MessageOutgoing,
|
||||
components: { MessageOutgoing },
|
||||
components: { MessageOutgoing, ThumbnailView },
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
|
|
|||
|
|
@ -5,6 +5,20 @@
|
|||
<video :src="src" controls class="w-100 h-100">
|
||||
{{$t('fallbacks.video_file')}}
|
||||
</video>
|
||||
<div v-if="downloadProgress" class="download-overlay">
|
||||
<div class="text-center download-text">
|
||||
{{ $t('message.download_progress',{percentage: downloadProgress}) }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="userInitiatedDownloadsOnly && !src" class="download-overlay">
|
||||
<div class="text-center download-text">
|
||||
{{ fileName }}
|
||||
</div>
|
||||
<div class="text-center download-size">
|
||||
{{ fileSize }}
|
||||
</div>
|
||||
<v-icon size="32" color="white" class="clickable" @click="loadAttachmentSource(event, true)">download</v-icon>
|
||||
</div>
|
||||
</v-responsive>
|
||||
</div>
|
||||
</message-outgoing>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
src: null,
|
||||
downloadProgress: null
|
||||
downloadProgress: null,
|
||||
userInitiatedDownloadsOnly: false,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -21,14 +22,27 @@ export default {
|
|||
beforeDestroy() {
|
||||
this.loadAttachmentSource(null); // Release
|
||||
},
|
||||
computed: {
|
||||
fileName() {
|
||||
return util.getFileName(this.event);
|
||||
},
|
||||
fileSize() {
|
||||
return util.getFileSizeFormatted(this.event);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadAttachmentSource(event) {
|
||||
loadAttachmentSource(event, userInitiated = false) {
|
||||
if (this.src) {
|
||||
const objectUrl = this.src;
|
||||
this.src = null;
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
}
|
||||
if (event) {
|
||||
const fileSize = util.getFileSize(event);
|
||||
if (!userInitiated && (fileSize == 0 || fileSize > 1000000)) {
|
||||
this.userInitiatedDownloadsOnly = true;
|
||||
return;
|
||||
}
|
||||
util
|
||||
.getAttachment(this.$matrix.matrixClient, event, (progress) => {
|
||||
this.downloadProgress = progress;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<template>
|
||||
<message-incoming v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
|
||||
<audio controls :src="src">{{ $t("fallbacks.audio_file") }}</audio>
|
||||
<audio controls>{{ $t("fallbacks.audio_file") }}</audio>
|
||||
</message-incoming>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import attachmentMixin from "../attachmentMixin";
|
||||
import exportedAttachmentMixin from "./exportedAttachmentMixin";
|
||||
import MessageIncoming from "../MessageIncoming.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageIncomingAudioExport",
|
||||
extends: MessageIncoming,
|
||||
mixins: [attachmentMixin],
|
||||
mixins: [exportedAttachmentMixin],
|
||||
components: { MessageIncoming },
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
51
src/components/messages/export/MessageIncomingFileExport.vue
Normal file
51
src/components/messages/export/MessageIncomingFileExport.vue
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<message-incoming v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
|
||||
<a style="text-decoration: none;color: currentColor" class="bubble" target="_blank" :href="href" >
|
||||
<div :class="{ 'thumbnail-item': true, 'preview': true, 'file-item': true }">
|
||||
<b>{{ $sanitize(fileName) }}</b>
|
||||
<div>{{ fileSize }}</div>
|
||||
</div>
|
||||
</a>
|
||||
</message-incoming>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import exportedAttachmentMixin from "./exportedAttachmentMixin";
|
||||
import MessageIncoming from "../MessageIncoming.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageIncomingFileExport",
|
||||
extends: MessageIncoming,
|
||||
mixins: [exportedAttachmentMixin],
|
||||
components: { MessageIncoming },
|
||||
data() {
|
||||
return {
|
||||
href: ""
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/assets/css/chat.scss";
|
||||
|
||||
.thumbnail-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.6rem;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
.v-icon {
|
||||
margin-bottom: 10px;
|
||||
color: currentColor;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
<message-incoming v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
|
||||
<div class="bubble image-bubble">
|
||||
<v-responsive :aspect-ratio="16 / 9" :src="src">
|
||||
<video :src="src" controls class="w-100 h-100">
|
||||
<video controls class="w-100 h-100">
|
||||
{{ $t("fallbacks.video_file") }}
|
||||
</video>
|
||||
</v-responsive>
|
||||
|
|
@ -11,14 +11,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import attachmentMixin from "../attachmentMixin";
|
||||
import exportedAttachmentMixin from "./exportedAttachmentMixin";
|
||||
import MessageIncoming from "../MessageIncoming.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageIncomingVideoExport",
|
||||
extends: MessageIncoming,
|
||||
components: { MessageIncoming },
|
||||
mixins: [attachmentMixin],
|
||||
mixins: [exportedAttachmentMixin],
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
<template>
|
||||
<message-outgoing v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
|
||||
<audio controls :src="src">{{ $t("fallbacks.audio_file") }}</audio>
|
||||
<audio controls>{{ $t("fallbacks.audio_file") }}</audio>
|
||||
</message-outgoing>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import attachmentMixin from "../attachmentMixin";
|
||||
import exportedAttachmentMixin from "./exportedAttachmentMixin";
|
||||
import MessageOutgoing from "../MessageOutgoing.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageOutgoingAudioExport",
|
||||
extends: MessageOutgoing,
|
||||
components: { MessageOutgoing },
|
||||
mixins: [attachmentMixin],
|
||||
mixins: [exportedAttachmentMixin],
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
51
src/components/messages/export/MessageOutgoingFileExport.vue
Normal file
51
src/components/messages/export/MessageOutgoingFileExport.vue
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<message-outgoing v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
|
||||
<a style="text-decoration: none;color: currentColor" class="bubble" target="_blank" :href="href" >
|
||||
<div :class="{ 'thumbnail-item': true, 'preview': true, 'file-item': true }">
|
||||
<b>{{ $sanitize(fileName) }}</b>
|
||||
<div>{{ fileSize }}</div>
|
||||
</div>
|
||||
</a>
|
||||
</message-outgoing>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import exportedAttachmentMixin from "./exportedAttachmentMixin";
|
||||
import MessageOutgoing from "../MessageOutgoing.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageOutgoingFileExport",
|
||||
extends: MessageOutgoing,
|
||||
mixins: [exportedAttachmentMixin],
|
||||
components: { MessageOutgoing },
|
||||
data() {
|
||||
return {
|
||||
href: ""
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/assets/css/chat.scss";
|
||||
|
||||
.thumbnail-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.6rem;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
.v-icon {
|
||||
margin-bottom: 10px;
|
||||
color: currentColor;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
<message-outgoing v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
|
||||
<div class="bubble image-bubble">
|
||||
<v-responsive :aspect-ratio="16 / 9" class="ma-0 pa-0">
|
||||
<video :src="src" controls class="w-100 h-100">
|
||||
<video controls class="w-100 h-100">
|
||||
{{ $t("fallbacks.video_file") }}
|
||||
</video>
|
||||
</v-responsive>
|
||||
|
|
@ -11,14 +11,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import attachmentMixin from "../attachmentMixin";
|
||||
import exportedAttachmentMixin from "./exportedAttachmentMixin";
|
||||
import MessageOutgoing from "../MessageOutgoing.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageOutgoingVideoExport",
|
||||
extends: MessageOutgoing,
|
||||
components: { MessageOutgoing },
|
||||
mixins: [attachmentMixin],
|
||||
mixins: [exportedAttachmentMixin],
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
17
src/components/messages/export/exportedAttachmentMixin.js
Normal file
17
src/components/messages/export/exportedAttachmentMixin.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import util from "../../../plugins/utils";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
src: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fileName() {
|
||||
return util.getFileName(this.event);
|
||||
},
|
||||
fileSize() {
|
||||
return util.getFileSizeFormatted(this.event);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ export default {
|
|||
if (item.status !== this.sendStatuses.INITIAL) {
|
||||
return getItemPromise(++index);
|
||||
}
|
||||
const itemPromise = util.sendImage(this.$matrix.matrixClient, this.room.roomId, item.attachment, ({ loaded, total }) => {
|
||||
const itemPromise = util.sendFile(this.$matrix.matrixClient, this.room.roomId, item.attachment, ({ loaded, total }) => {
|
||||
if (loaded == total) {
|
||||
item.progress = 100;
|
||||
} else if (total > 0) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import dataUriToBuffer from "data-uri-to-buffer";
|
|||
import ImageResize from "image-resize";
|
||||
import { AutoDiscovery } from 'matrix-js-sdk';
|
||||
import User from '../models/user';
|
||||
const prettyBytes = require("pretty-bytes");
|
||||
|
||||
export const STATE_EVENT_ROOM_DELETION_NOTICE = "im.keanu.room_deletion_notice";
|
||||
export const STATE_EVENT_ROOM_DELETED = "im.keanu.room_deleted";
|
||||
|
|
@ -159,7 +160,7 @@ class Util {
|
|||
// true
|
||||
// );
|
||||
url = matrixClient.mxcUrlToHttp(file.url);
|
||||
} else if (content.file && content.file.url) {
|
||||
} else if (content.file && content.file.url && this.getMimeType(event).startsWith("image/")) {
|
||||
// No thumb, use real url
|
||||
file = content.file;
|
||||
url = matrixClient.mxcUrlToHttp(file.url);
|
||||
|
|
@ -348,7 +349,7 @@ class Util {
|
|||
});
|
||||
}
|
||||
|
||||
sendImage(matrixClient, roomId, file, onUploadProgress, threadRoot) {
|
||||
sendFile(matrixClient, roomId, file, onUploadProgress, threadRoot) {
|
||||
const uploadPromise = new UploadPromise(undefined);
|
||||
uploadPromise.wrappedPromise = new Promise((resolve, reject) => {
|
||||
var reader = new FileReader();
|
||||
|
|
@ -371,13 +372,13 @@ class Util {
|
|||
}
|
||||
|
||||
var description = file.name;
|
||||
var msgtype = 'm.image';
|
||||
if (file.type.startsWith("audio/")) {
|
||||
var msgtype = 'm.file';
|
||||
if (file.type.startsWith("image/")) {
|
||||
msgtype = 'm.image';
|
||||
} else if (file.type.startsWith("audio/")) {
|
||||
msgtype = 'm.audio';
|
||||
} else if (file.type.startsWith("video/")) {
|
||||
msgtype = 'm.video';
|
||||
} else if (file.type.startsWith("application/pdf")) {
|
||||
msgtype = 'm.file';
|
||||
}
|
||||
|
||||
const opts = {
|
||||
|
|
@ -913,7 +914,6 @@ class Util {
|
|||
link.download = event.getContent().body || this.$t("fallbacks.download_name");
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
setTimeout(function () {
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
|
|
@ -951,6 +951,68 @@ class Util {
|
|||
}
|
||||
return Promise.resolve(config.defaultBaseUrl);
|
||||
}
|
||||
|
||||
getMimeType(event) {
|
||||
const content = event.getContent();
|
||||
return (content.info && content.info.mimetype) ? content.info.mimetype : (content.file && content.file.mimetype) ? content.file.mimetype : "";
|
||||
}
|
||||
|
||||
getFileName(event) {
|
||||
const content = event.getContent();
|
||||
return (content.body || content.filename || "").toLowerCase();
|
||||
}
|
||||
|
||||
getFileExtension(event) {
|
||||
const fileName = this.getFileName(event);
|
||||
const parts = fileName.split(".");
|
||||
if (parts.length > 1) {
|
||||
return "." + parts[parts.length - 1].toLowerCase();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
getFileSize(event) {
|
||||
const content = event.getContent();
|
||||
if (content.info) {
|
||||
return content.info.size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getFileSizeFormatted(event) {
|
||||
return prettyBytes(this.getFileSize(event));
|
||||
}
|
||||
|
||||
isFileTypeAPK(event) {
|
||||
const mime = this.getMimeType(event);
|
||||
if (mime === "application/vnd.android.package-archive" || this.getFileName(event).endsWith(".apk")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isFileTypeIPA(event) {
|
||||
if (this.getFileName(event).endsWith(".ipa")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isFileTypePDF(event) {
|
||||
const mime = this.getMimeType(event);
|
||||
if (mime === "application/pdf" || this.getFileName(event).endsWith(".pdf")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isFileTypeZip(event) {
|
||||
const mime = this.getMimeType(event);
|
||||
if (["application/zip", "application/x-zip-compressed", "multipart/x-zip"].includes(mime) || this.getFileName(event).endsWith(".zip")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export default new Util();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue