Send multiple files
Refactor sendAlbum
This commit is contained in:
parent
2580c4e720
commit
eda9f5a306
@ -30,7 +30,7 @@ import AudioElement from "../audio";
|
|||||||
import AvatarElement from "../avatar";
|
import AvatarElement from "../avatar";
|
||||||
import { formatPhoneNumber } from "../misc";
|
import { formatPhoneNumber } from "../misc";
|
||||||
import { ripple } from "../ripple";
|
import { ripple } from "../ripple";
|
||||||
import { wrapAlbum, wrapPhoto, wrapVideo, wrapDocument, wrapSticker, wrapPoll, wrapReply } from "../wrappers";
|
import { wrapAlbum, wrapPhoto, wrapVideo, wrapDocument, wrapSticker, wrapPoll, wrapReply, wrapGroupedDocuments } from "../wrappers";
|
||||||
import { MessageRender } from "./messageRender";
|
import { MessageRender } from "./messageRender";
|
||||||
import LazyLoadQueue from "../lazyLoadQueue";
|
import LazyLoadQueue from "../lazyLoadQueue";
|
||||||
import { AppChatsManager } from "../../lib/appManagers/appChatsManager";
|
import { AppChatsManager } from "../../lib/appManagers/appChatsManager";
|
||||||
@ -196,20 +196,18 @@ export default class ChatBubbles {
|
|||||||
const message = this.appMessagesManager.getMessage(mid);
|
const message = this.appMessagesManager.getMessage(mid);
|
||||||
|
|
||||||
appSidebarRight.sharedMediaTab.renderNewMessages(message.peerID, [mid]);
|
appSidebarRight.sharedMediaTab.renderNewMessages(message.peerID, [mid]);
|
||||||
|
|
||||||
const bubble = this.bubbles[tempID];
|
const mounted = this.getMountedBubble(tempID) || this.getMountedBubble(mid);
|
||||||
if(bubble) {
|
if(mounted) {
|
||||||
this.bubbles[mid] = bubble;
|
const bubble = mounted.bubble;
|
||||||
|
//this.bubbles[mid] = bubble;
|
||||||
|
|
||||||
/////this.log('message_sent', bubble);
|
/////this.log('message_sent', bubble);
|
||||||
|
|
||||||
// set new mids to album items for mediaViewer
|
// set new mids to album items for mediaViewer
|
||||||
if(message.grouped_id) {
|
if(message.grouped_id) {
|
||||||
const items = bubble.querySelectorAll('.grouped-item');
|
const item = bubble.querySelector(`.grouped-item[data-mid="${tempID}"]`) as HTMLElement;
|
||||||
const groupIDs = getObjectKeysAndSort(appMessagesManager.groupedMessagesStorage[message.grouped_id]);
|
item.dataset.mid = '' + mid;
|
||||||
(Array.from(items) as HTMLElement[]).forEach((item, idx) => {
|
|
||||||
item.dataset.mid = '' + groupIDs[idx];
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(message.media?.poll) {
|
if(message.media?.poll) {
|
||||||
@ -222,16 +220,16 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(['audio', 'voice'].includes(message.media?.document?.type)) {
|
if(['audio', 'voice'].includes(message.media?.document?.type)) {
|
||||||
const audio = bubble.querySelector('audio-element');
|
const audio = bubble.querySelector(`audio-element[message-id="${tempID}"]`);
|
||||||
audio.setAttribute('doc-id', message.media.document.id);
|
audio.setAttribute('doc-id', message.media.document.id);
|
||||||
audio.setAttribute('message-id', '' + mid);
|
audio.setAttribute('message-id', '' + mid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bubble.classList.remove('is-sending');
|
/* bubble.classList.remove('is-sending');
|
||||||
bubble.classList.add('is-sent');
|
bubble.classList.add('is-sent');
|
||||||
bubble.dataset.mid = '' + mid;
|
bubble.dataset.mid = '' + mid;
|
||||||
|
|
||||||
this.bubbleGroups.removeBubble(bubble, tempID);
|
this.bubbleGroups.removeBubble(bubble, tempID); */
|
||||||
|
|
||||||
if(message.media?.webpage && !bubble.querySelector('.web')) {
|
if(message.media?.webpage && !bubble.querySelector('.web')) {
|
||||||
const mounted = this.getMountedBubble(mid);
|
const mounted = this.getMountedBubble(mid);
|
||||||
@ -239,11 +237,23 @@ export default class ChatBubbles {
|
|||||||
this.renderMessage(mounted.message, true, false, mounted.bubble, false);
|
this.renderMessage(mounted.message, true, false, mounted.bubble, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete this.bubbles[tempID];
|
//delete this.bubbles[tempID];
|
||||||
} else {
|
} else {
|
||||||
this.log.warn('message_sent there is no bubble', e.detail);
|
this.log.warn('message_sent there is no bubble', e.detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this.bubbles[tempID]) {
|
||||||
|
const bubble = this.bubbles[tempID];
|
||||||
|
this.bubbles[mid] = bubble;
|
||||||
|
delete this.bubbles[tempID];
|
||||||
|
|
||||||
|
bubble.classList.remove('is-sending');
|
||||||
|
bubble.classList.add('is-sent');
|
||||||
|
bubble.dataset.mid = '' + mid;
|
||||||
|
|
||||||
|
this.bubbleGroups.removeBubble(bubble, tempID);
|
||||||
|
}
|
||||||
|
|
||||||
if(this.unreadOut.has(tempID)) {
|
if(this.unreadOut.has(tempID)) {
|
||||||
this.unreadOut.delete(tempID);
|
this.unreadOut.delete(tempID);
|
||||||
this.unreadOut.add(mid);
|
this.unreadOut.add(mid);
|
||||||
@ -1360,7 +1370,7 @@ export default class ChatBubbles {
|
|||||||
let messageMedia = message.media;
|
let messageMedia = message.media;
|
||||||
|
|
||||||
let messageMessage: string, totalEntities: any[];
|
let messageMessage: string, totalEntities: any[];
|
||||||
if(messageMedia?.document && !messageMedia.document.type) {
|
if(messageMedia?.document && messageMedia.document.type !== 'video') {
|
||||||
// * just filter this case
|
// * just filter this case
|
||||||
} else if(message.grouped_id && albumMustBeRenderedFull) {
|
} else if(message.grouped_id && albumMustBeRenderedFull) {
|
||||||
const t = this.appMessagesManager.getAlbumText(message.grouped_id);
|
const t = this.appMessagesManager.getAlbumText(message.grouped_id);
|
||||||
@ -1575,25 +1585,23 @@ export default class ChatBubbles {
|
|||||||
case 'audio':
|
case 'audio':
|
||||||
case 'voice':
|
case 'voice':
|
||||||
case 'document': {
|
case 'document': {
|
||||||
const doc = this.appDocsManager.getDoc(message.id);
|
const newNameContainer = wrapGroupedDocuments({
|
||||||
//if(doc._ == 'documentEmpty') break;
|
albumMustBeRenderedFull,
|
||||||
this.log('will wrap pending doc:', doc);
|
message,
|
||||||
const docDiv = wrapDocument(doc, false, true, message.id);
|
bubble,
|
||||||
|
messageDiv
|
||||||
if(doc.type == 'audio' || doc.type == 'voice') {
|
});
|
||||||
(docDiv as AudioElement).preloader = preloader;
|
|
||||||
} else {
|
if(newNameContainer) {
|
||||||
const icoDiv = docDiv.querySelector('.audio-download, .document-ico');
|
nameContainer = newNameContainer;
|
||||||
preloader.attach(icoDiv, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pending.type == 'voice') {
|
if(pending.type == 'voice') {
|
||||||
bubble.classList.add('bubble-audio');
|
bubble.classList.add('bubble-audio');
|
||||||
}
|
}
|
||||||
|
|
||||||
bubble.classList.remove('is-message-empty');
|
bubble.classList.remove('is-message-empty');
|
||||||
messageDiv.classList.add((pending.type || 'document') + '-message');
|
messageDiv.classList.add((pending.type || 'document') + '-message');
|
||||||
messageDiv.append(docDiv);
|
|
||||||
processingWebPage = true;
|
processingWebPage = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1805,52 +1813,15 @@ export default class ChatBubbles {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
//const storage = this.appMessagesManager.groupedMessagesStorage[message.grouped_id];
|
const newNameContainer = wrapGroupedDocuments({
|
||||||
//const isFullAlbum = storage && Object.keys(storage).length != 1;
|
albumMustBeRenderedFull,
|
||||||
const mids = albumMustBeRenderedFull ? this.appMessagesManager.getMidsByMid(message.mid) : [message.mid];
|
message,
|
||||||
mids.forEach((mid, idx) => {
|
bubble,
|
||||||
const message = this.appMessagesManager.getMessage(mid);
|
messageDiv
|
||||||
const doc = message.media.document;
|
|
||||||
const div = wrapDocument(doc, false, false, mid);
|
|
||||||
|
|
||||||
const container = document.createElement('div');
|
|
||||||
container.classList.add('document-container');
|
|
||||||
container.dataset.mid = '' + mid;
|
|
||||||
|
|
||||||
const wrapper = document.createElement('div');
|
|
||||||
wrapper.classList.add('document-wrapper');
|
|
||||||
|
|
||||||
if(message.message) {
|
|
||||||
const messageDiv = document.createElement('div');
|
|
||||||
messageDiv.classList.add('document-message');
|
|
||||||
|
|
||||||
const richText = RichTextProcessor.wrapRichText(message.message, {
|
|
||||||
entities: message.totalEntities
|
|
||||||
});
|
|
||||||
|
|
||||||
messageDiv.innerHTML = richText;
|
|
||||||
wrapper.append(messageDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mids.length > 1) {
|
|
||||||
const selection = document.createElement('div');
|
|
||||||
selection.classList.add('document-selection');
|
|
||||||
container.append(selection);
|
|
||||||
|
|
||||||
container.classList.add('grouped-item');
|
|
||||||
|
|
||||||
if(idx === 0) {
|
|
||||||
nameContainer = wrapper;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapper.append(div);
|
|
||||||
container.append(wrapper);
|
|
||||||
messageDiv.append(container);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if(mids.length > 1) {
|
if(newNameContainer) {
|
||||||
bubble.classList.add('is-multiple-documents', 'is-grouped');
|
nameContainer = newNameContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bubble.classList.remove('is-message-empty');
|
bubble.classList.remove('is-message-empty');
|
||||||
|
@ -8,6 +8,7 @@ import { ripple } from "./ripple";
|
|||||||
import Scrollable from "./scrollable";
|
import Scrollable from "./scrollable";
|
||||||
import { toast } from "./toast";
|
import { toast } from "./toast";
|
||||||
import { prepareAlbum, wrapDocument } from "./wrappers";
|
import { prepareAlbum, wrapDocument } from "./wrappers";
|
||||||
|
import CheckboxField from "./checkbox";
|
||||||
|
|
||||||
type SendFileParams = Partial<{
|
type SendFileParams = Partial<{
|
||||||
file: File,
|
file: File,
|
||||||
@ -25,13 +26,16 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
private btnSend: HTMLElement;
|
private btnSend: HTMLElement;
|
||||||
private input: HTMLInputElement;
|
private input: HTMLInputElement;
|
||||||
private mediaContainer: HTMLElement;
|
private mediaContainer: HTMLElement;
|
||||||
|
private groupCheckboxField: { label: HTMLLabelElement; input: HTMLInputElement; span: HTMLSpanElement; };
|
||||||
|
|
||||||
private willAttach: Partial<{
|
private willAttach: Partial<{
|
||||||
type: 'media' | 'document',
|
type: 'media' | 'document',
|
||||||
isMedia: boolean,
|
isMedia: true,
|
||||||
|
group: boolean,
|
||||||
sendFileDetails: SendFileParams[]
|
sendFileDetails: SendFileParams[]
|
||||||
}> = {
|
}> = {
|
||||||
sendFileDetails: []
|
sendFileDetails: [],
|
||||||
|
group: false
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(files: File[], willAttachType: PopupNewMedia['willAttach']['type']) {
|
constructor(files: File[], willAttachType: PopupNewMedia['willAttach']['type']) {
|
||||||
@ -60,7 +64,29 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
showLengthOn: 80
|
showLengthOn: 80
|
||||||
});
|
});
|
||||||
this.input = inputField.input;
|
this.input = inputField.input;
|
||||||
this.container.append(scrollable.container, inputField.container);
|
|
||||||
|
this.container.append(scrollable.container);
|
||||||
|
|
||||||
|
if(files.length > 1) {
|
||||||
|
this.groupCheckboxField = CheckboxField('Group items', 'group-items');
|
||||||
|
this.container.append(this.groupCheckboxField.label, inputField.container);
|
||||||
|
|
||||||
|
this.groupCheckboxField.input.checked = true;
|
||||||
|
this.willAttach.group = true;
|
||||||
|
|
||||||
|
this.groupCheckboxField.input.addEventListener('change', () => {
|
||||||
|
const checked = this.groupCheckboxField.input.checked;
|
||||||
|
|
||||||
|
this.willAttach.group = checked;
|
||||||
|
this.willAttach.sendFileDetails.length = 0;
|
||||||
|
|
||||||
|
//this.mediaContainer.innerHTML = '';
|
||||||
|
//this.container.classList.remove('is-media', 'is-document', 'is-album');
|
||||||
|
this.attachFiles(files);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.container.append(inputField.container);
|
||||||
|
|
||||||
this.attachFiles(files);
|
this.attachFiles(files);
|
||||||
}
|
}
|
||||||
@ -85,18 +111,35 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
|
|
||||||
this.destroy();
|
this.destroy();
|
||||||
const willAttach = this.willAttach;
|
const willAttach = this.willAttach;
|
||||||
willAttach.isMedia = willAttach.type == 'media';
|
willAttach.isMedia = willAttach.type == 'media' ? true : undefined;
|
||||||
|
|
||||||
//console.log('will send files with options:', willAttach);
|
//console.log('will send files with options:', willAttach);
|
||||||
|
|
||||||
const peerID = appImManager.chat.peerID;
|
const peerID = appImManager.chat.peerID;
|
||||||
const chatInputC = appImManager.chat.input;
|
const chatInputC = appImManager.chat.input;
|
||||||
|
|
||||||
if(willAttach.sendFileDetails.length > 1 && willAttach.isMedia) {
|
if(willAttach.sendFileDetails.length > 1 && willAttach.group) {
|
||||||
appMessagesManager.sendAlbum(peerID, willAttach.sendFileDetails.map(d => d.file), Object.assign({
|
for(let i = 0; i < willAttach.sendFileDetails.length;) {
|
||||||
caption,
|
let firstType = willAttach.sendFileDetails[i].file.type.split('/')[0];
|
||||||
replyToMsgID: chatInputC.replyToMsgID
|
for(var k = 0; k < 10 && i < willAttach.sendFileDetails.length; ++i, ++k) {
|
||||||
}, willAttach));
|
const type = willAttach.sendFileDetails[i].file.type.split('/')[0];
|
||||||
|
if(firstType != type) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const w = {...willAttach};
|
||||||
|
w.sendFileDetails = willAttach.sendFileDetails.slice(i - k, i);
|
||||||
|
|
||||||
|
appMessagesManager.sendAlbum(peerID, w.sendFileDetails.map(d => d.file), Object.assign({
|
||||||
|
caption,
|
||||||
|
replyToMsgID: chatInputC.replyToMsgID,
|
||||||
|
isMedia: willAttach.isMedia
|
||||||
|
}, w));
|
||||||
|
|
||||||
|
caption = undefined;
|
||||||
|
chatInputC.replyToMsgID = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if(caption) {
|
if(caption) {
|
||||||
if(willAttach.sendFileDetails.length > 1) {
|
if(willAttach.sendFileDetails.length > 1) {
|
||||||
@ -109,7 +152,7 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
const promises = willAttach.sendFileDetails.map(params => {
|
const promises = willAttach.sendFileDetails.map(params => {
|
||||||
const promise = appMessagesManager.sendFile(peerID, params.file, Object.assign({
|
const promise = appMessagesManager.sendFile(peerID, params.file, Object.assign({
|
||||||
//isMedia: willAttach.isMedia,
|
//isMedia: willAttach.isMedia,
|
||||||
isMedia: params.file.type.includes('audio/') || willAttach.isMedia,
|
isMedia: willAttach.isMedia,
|
||||||
caption,
|
caption,
|
||||||
replyToMsgID: chatInputC.replyToMsgID
|
replyToMsgID: chatInputC.replyToMsgID
|
||||||
}, params));
|
}, params));
|
||||||
@ -176,7 +219,8 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
|
|
||||||
case 'document': {
|
case 'document': {
|
||||||
const isPhoto = file.type.indexOf('image/') !== -1;
|
const isPhoto = file.type.indexOf('image/') !== -1;
|
||||||
if(isPhoto) {
|
const isAudio = file.type.indexOf('audio/') !== -1;
|
||||||
|
if(isPhoto || isAudio) {
|
||||||
params.objectURL = URL.createObjectURL(file);
|
params.objectURL = URL.createObjectURL(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,9 +264,9 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
const container = this.container;
|
const container = this.container;
|
||||||
const willAttach = this.willAttach;
|
const willAttach = this.willAttach;
|
||||||
|
|
||||||
if(files.length > 10 && willAttach.type == 'media') {
|
/* if(files.length > 10 && willAttach.type == 'media') {
|
||||||
willAttach.type = 'document';
|
willAttach.type = 'document';
|
||||||
}
|
} */
|
||||||
|
|
||||||
files = files.filter(file => {
|
files = files.filter(file => {
|
||||||
if(willAttach.type == 'media') {
|
if(willAttach.type == 'media') {
|
||||||
@ -232,64 +276,77 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(files.length) {
|
Promise.all(files.map(this.attachFile)).then(results => {
|
||||||
if(willAttach.type == 'document') {
|
this.container.classList.remove('is-media', 'is-document', 'is-album');
|
||||||
this.title.innerText = 'Send ' + (files.length > 1 ? files.length + ' Files' : 'File');
|
this.mediaContainer.innerHTML = '';
|
||||||
container.classList.add('is-document');
|
|
||||||
} else {
|
|
||||||
container.classList.add('is-media');
|
|
||||||
|
|
||||||
let foundPhotos = 0;
|
if(files.length) {
|
||||||
let foundVideos = 0;
|
if(willAttach.type == 'document') {
|
||||||
files.forEach(file => {
|
this.title.innerText = 'Send ' + (files.length > 1 ? files.length + ' Files' : 'File');
|
||||||
if(file.type.indexOf('image/') === 0) ++foundPhotos;
|
container.classList.add('is-document');
|
||||||
else if(file.type.indexOf('video/') === 0) ++foundVideos;
|
} else {
|
||||||
});
|
container.classList.add('is-media');
|
||||||
|
|
||||||
if(foundPhotos && foundVideos) {
|
let foundPhotos = 0;
|
||||||
this.title.innerText = 'Send Album';
|
let foundVideos = 0;
|
||||||
} else if(foundPhotos) {
|
files.forEach(file => {
|
||||||
this.title.innerText = 'Send ' + (foundPhotos > 1 ? foundPhotos + ' Photos' : 'Photo');
|
if(file.type.indexOf('image/') === 0) ++foundPhotos;
|
||||||
} else if(foundVideos) {
|
else if(file.type.indexOf('video/') === 0) ++foundVideos;
|
||||||
this.title.innerText = 'Send ' + (foundVideos > 1 ? foundVideos + ' Videos' : 'Video');
|
});
|
||||||
|
|
||||||
|
if(foundPhotos && foundVideos && willAttach.group) {
|
||||||
|
this.title.innerText = 'Send Album';
|
||||||
|
} else if(foundPhotos) {
|
||||||
|
this.title.innerText = 'Send ' + (foundPhotos > 1 ? foundPhotos + ' Photos' : 'Photo');
|
||||||
|
} else if(foundVideos) {
|
||||||
|
this.title.innerText = 'Send ' + (foundVideos > 1 ? foundVideos + ' Videos' : 'Video');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Promise.all(files.map(this.attachFile)).then(results => {
|
|
||||||
if(willAttach.type == 'media') {
|
if(willAttach.type == 'media') {
|
||||||
if(willAttach.sendFileDetails.length > 1) {
|
if(willAttach.sendFileDetails.length > 1 && willAttach.group) {
|
||||||
container.classList.add('is-album');
|
container.classList.add('is-album');
|
||||||
|
|
||||||
this.mediaContainer.append(...results);
|
for(let i = 0; i < results.length; i += 10) {
|
||||||
|
const albumContainer = document.createElement('div');
|
||||||
|
albumContainer.classList.add('popup-album');
|
||||||
|
|
||||||
prepareAlbum({
|
albumContainer.append(...results.slice(i, i + 10));
|
||||||
container: this.mediaContainer,
|
prepareAlbum({
|
||||||
items: willAttach.sendFileDetails.map(o => ({w: o.width, h: o.height})),
|
container: albumContainer,
|
||||||
maxWidth: 380,
|
items: willAttach.sendFileDetails.slice(i, i + 10).map(o => ({w: o.width, h: o.height})),
|
||||||
minWidth: 100,
|
maxWidth: 380,
|
||||||
spacing: 4
|
minWidth: 100,
|
||||||
});
|
spacing: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
this.mediaContainer.append(albumContainer);
|
||||||
|
}
|
||||||
|
|
||||||
//console.log('chatInput album layout:', layout);
|
//console.log('chatInput album layout:', layout);
|
||||||
} else {
|
} else {
|
||||||
const params = willAttach.sendFileDetails[0];
|
for(let i = 0; i < results.length; ++i) {
|
||||||
const div = results[0];
|
const params = willAttach.sendFileDetails[i];
|
||||||
const {w, h} = calcImageInBox(params.width, params.height, 380, 320);
|
const div = results[i];
|
||||||
div.style.width = w + 'px';
|
const {w, h} = calcImageInBox(params.width, params.height, 380, 320);
|
||||||
div.style.height = h + 'px';
|
div.style.width = w + 'px';
|
||||||
this.mediaContainer.append(div);
|
div.style.height = h + 'px';
|
||||||
|
this.mediaContainer.append(div);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.mediaContainer.append(...results);
|
this.mediaContainer.append(...results);
|
||||||
}
|
}
|
||||||
|
|
||||||
// show now
|
// show now
|
||||||
document.body.addEventListener('keydown', this.onKeyDown);
|
if(!this.element.classList.contains('active')) {
|
||||||
this.onClose = () => {
|
document.body.addEventListener('keydown', this.onKeyDown);
|
||||||
document.body.removeEventListener('keydown', this.onKeyDown);
|
this.onClose = () => {
|
||||||
};
|
document.body.removeEventListener('keydown', this.onKeyDown);
|
||||||
this.show();
|
};
|
||||||
|
this.show();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import PollElement from './poll';
|
|||||||
import ProgressivePreloader from './preloader';
|
import ProgressivePreloader from './preloader';
|
||||||
import './middleEllipsis';
|
import './middleEllipsis';
|
||||||
import { nextRandomInt } from '../helpers/random';
|
import { nextRandomInt } from '../helpers/random';
|
||||||
|
import RichTextProcessor from '../lib/richtextprocessor';
|
||||||
|
|
||||||
const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB
|
const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB
|
||||||
|
|
||||||
@ -337,7 +338,7 @@ export function wrapDocument(doc: MyDocument, withTime = false, uploading = fals
|
|||||||
const icoDiv = document.createElement('div');
|
const icoDiv = document.createElement('div');
|
||||||
icoDiv.classList.add('document-ico');
|
icoDiv.classList.add('document-ico');
|
||||||
|
|
||||||
if(doc.thumbs?.length || (uploading && doc.url)) {
|
if(doc.thumbs?.length || (uploading && doc.url && doc.type == 'photo')) {
|
||||||
docDiv.classList.add('document-with-thumb');
|
docDiv.classList.add('document-with-thumb');
|
||||||
|
|
||||||
if(uploading) {
|
if(uploading) {
|
||||||
@ -858,7 +859,7 @@ export function wrapAlbum({groupID, attachmentDiv, middleware, uploading, lazyLo
|
|||||||
}) {
|
}) {
|
||||||
const items: {size: PhotoSize.photoSize, media: any, message: any}[] = [];
|
const items: {size: PhotoSize.photoSize, media: any, message: any}[] = [];
|
||||||
|
|
||||||
// !higher msgID will be the FIRST in album
|
// !lowest msgID will be the FIRST in album
|
||||||
const storage = appMessagesManager.getMidsByAlbum(groupID);
|
const storage = appMessagesManager.getMidsByAlbum(groupID);
|
||||||
for(const mid of storage) {
|
for(const mid of storage) {
|
||||||
const m = appMessagesManager.getMessage(mid);
|
const m = appMessagesManager.getMessage(mid);
|
||||||
@ -868,6 +869,11 @@ export function wrapAlbum({groupID, attachmentDiv, middleware, uploading, lazyLo
|
|||||||
items.push({size, media, message: m});
|
items.push({size, media, message: m});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// * pending
|
||||||
|
if(storage[0] < 0) {
|
||||||
|
items.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
prepareAlbum({
|
prepareAlbum({
|
||||||
container: attachmentDiv,
|
container: attachmentDiv,
|
||||||
items: items.map(i => ({w: i.size.w, h: i.size.h})),
|
items: items.map(i => ({w: i.size.w, h: i.size.h})),
|
||||||
@ -912,6 +918,77 @@ export function wrapAlbum({groupID, attachmentDiv, middleware, uploading, lazyLo
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function wrapGroupedDocuments({albumMustBeRenderedFull, message, bubble, messageDiv}: {
|
||||||
|
albumMustBeRenderedFull: boolean,
|
||||||
|
message: any,
|
||||||
|
messageDiv: HTMLElement,
|
||||||
|
bubble: HTMLElement,
|
||||||
|
uploading?: boolean
|
||||||
|
}) {
|
||||||
|
let nameContainer: HTMLDivElement;
|
||||||
|
const mids = albumMustBeRenderedFull ? appMessagesManager.getMidsByMid(message.mid) : [message.mid];
|
||||||
|
const isPending = message.mid < 0;
|
||||||
|
if(isPending) {
|
||||||
|
mids.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
mids.forEach((mid, idx) => {
|
||||||
|
const message = appMessagesManager.getMessage(mid);
|
||||||
|
const doc = message.media.document;
|
||||||
|
const div = wrapDocument(doc, false, isPending, mid);
|
||||||
|
|
||||||
|
const container = document.createElement('div');
|
||||||
|
container.classList.add('document-container');
|
||||||
|
container.dataset.mid = '' + mid;
|
||||||
|
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
wrapper.classList.add('document-wrapper');
|
||||||
|
|
||||||
|
if(message.message) {
|
||||||
|
const messageDiv = document.createElement('div');
|
||||||
|
messageDiv.classList.add('document-message');
|
||||||
|
|
||||||
|
const richText = RichTextProcessor.wrapRichText(message.message, {
|
||||||
|
entities: message.totalEntities
|
||||||
|
});
|
||||||
|
|
||||||
|
messageDiv.innerHTML = richText;
|
||||||
|
wrapper.append(messageDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mids.length > 1) {
|
||||||
|
const selection = document.createElement('div');
|
||||||
|
selection.classList.add('document-selection');
|
||||||
|
container.append(selection);
|
||||||
|
|
||||||
|
container.classList.add('grouped-item');
|
||||||
|
|
||||||
|
if(idx === 0) {
|
||||||
|
nameContainer = wrapper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isPending) {
|
||||||
|
if(doc.type == 'audio' || doc.type == 'voice') {
|
||||||
|
(div as AudioElement).preloader = message.media.preloader;
|
||||||
|
} else {
|
||||||
|
const icoDiv = div.querySelector('.audio-download, .document-ico');
|
||||||
|
message.media.preloader.attach(icoDiv, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper.append(div);
|
||||||
|
container.append(wrapper);
|
||||||
|
messageDiv.append(container);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(mids.length > 1) {
|
||||||
|
bubble.classList.add('is-multiple-documents', 'is-grouped');
|
||||||
|
}
|
||||||
|
|
||||||
|
return nameContainer;
|
||||||
|
}
|
||||||
|
|
||||||
export function wrapPoll(pollID: string, mid: number) {
|
export function wrapPoll(pollID: string, mid: number) {
|
||||||
const elem = new PollElement();
|
const elem = new PollElement();
|
||||||
elem.setAttribute('poll-id', pollID);
|
elem.setAttribute('poll-id', pollID);
|
||||||
|
@ -4,7 +4,7 @@ import { tsNow } from "../../helpers/date";
|
|||||||
import { copy, defineNotNumerableProperties, safeReplaceObject, getObjectKeysAndSort } from "../../helpers/object";
|
import { copy, defineNotNumerableProperties, safeReplaceObject, getObjectKeysAndSort } from "../../helpers/object";
|
||||||
import { randomLong } from "../../helpers/random";
|
import { randomLong } from "../../helpers/random";
|
||||||
import { splitStringByLength, limitSymbols } from "../../helpers/string";
|
import { splitStringByLength, limitSymbols } from "../../helpers/string";
|
||||||
import { Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMessage, InputNotifyPeer, InputPeerNotifySettings, Message, MessageAction, MessageEntity, MessagesDialogs, MessagesFilter, MessagesMessages, MessagesPeerDialogs, MethodDeclMap, NotifyPeer, PhotoSize, SendMessageAction, Update } from "../../layer";
|
import { Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputNotifyPeer, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessagesDialogs, MessagesFilter, MessagesMessages, MessagesPeerDialogs, MethodDeclMap, NotifyPeer, PhotoSize, SendMessageAction, Update } from "../../layer";
|
||||||
import { InvokeApiOptions } from "../../types";
|
import { InvokeApiOptions } from "../../types";
|
||||||
import { langPack } from "../langPack";
|
import { langPack } from "../langPack";
|
||||||
import { logger, LogLevels } from "../logger";
|
import { logger, LogLevels } from "../logger";
|
||||||
@ -569,31 +569,32 @@ export class AppMessagesManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public sendFile(peerID: number, file: File | Blob | MyDocument, options: Partial<{
|
public sendFile(peerID: number, file: File | Blob | MyDocument, options: Partial<{
|
||||||
isMedia: boolean,
|
isRoundMessage: true,
|
||||||
|
isVoiceMessage: true,
|
||||||
|
isGroupedItem: true,
|
||||||
|
isMedia: true,
|
||||||
|
|
||||||
replyToMsgID: number,
|
replyToMsgID: number,
|
||||||
caption: string,
|
caption: string,
|
||||||
entities: any[],
|
entities: MessageEntity[],
|
||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
objectURL: string,
|
objectURL: string,
|
||||||
isRoundMessage: boolean,
|
|
||||||
duration: number,
|
duration: number,
|
||||||
background: boolean,
|
background: true,
|
||||||
|
|
||||||
isVoiceMessage: boolean,
|
|
||||||
waveform: Uint8Array
|
waveform: Uint8Array
|
||||||
}> = {}) {
|
}> = {}) {
|
||||||
peerID = appPeersManager.getPeerMigratedTo(peerID) || peerID;
|
peerID = appPeersManager.getPeerMigratedTo(peerID) || peerID;
|
||||||
var messageID = this.tempID--;
|
const messageID = this.tempID--;
|
||||||
var randomIDS = randomLong();
|
const randomIDS = randomLong();
|
||||||
var historyStorage = this.historiesStorage[peerID] ?? (this.historiesStorage[peerID] = {count: null, history: [], pending: []});
|
const historyStorage = this.historiesStorage[peerID] ?? (this.historiesStorage[peerID] = {count: null, history: [], pending: []});
|
||||||
var flags = 0;
|
const pFlags: any = {};
|
||||||
var pFlags: any = {};
|
const replyToMsgID = options.replyToMsgID;
|
||||||
var replyToMsgID = options.replyToMsgID;
|
const isChannel = appPeersManager.isChannel(peerID);
|
||||||
var isChannel = appPeersManager.isChannel(peerID);
|
const isMegagroup = isChannel && appPeersManager.isMegagroup(peerID);
|
||||||
var isMegagroup = isChannel && appPeersManager.isMegagroup(peerID);
|
const asChannel = !!(isChannel && !isMegagroup);
|
||||||
var asChannel = isChannel && !isMegagroup ? true : false;
|
let attachType: string, apiFileName: string;
|
||||||
var attachType: string, apiFileName: string;
|
|
||||||
|
|
||||||
const fileType = 'mime_type' in file ? file.mime_type : file.type;
|
const fileType = 'mime_type' in file ? file.mime_type : file.type;
|
||||||
const fileName = file instanceof File ? file.name : '';
|
const fileName = file instanceof File ? file.name : '';
|
||||||
@ -613,20 +614,42 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
const isPhoto = ['image/jpeg', 'image/png', 'image/bmp'].indexOf(fileType) >= 0;
|
const isPhoto = ['image/jpeg', 'image/png', 'image/bmp'].indexOf(fileType) >= 0;
|
||||||
|
|
||||||
|
let photo: MyPhoto, document: MyDocument;
|
||||||
|
|
||||||
let actionName = '';
|
let actionName = '';
|
||||||
if(!options.isMedia) {
|
if(isDocument) { // maybe it's a sticker or gif
|
||||||
|
attachType = 'document';
|
||||||
|
apiFileName = '';
|
||||||
|
} else if(fileType.indexOf('audio/') === 0 || ['video/ogg'].indexOf(fileType) >= 0) {
|
||||||
|
attachType = 'audio';
|
||||||
|
apiFileName = 'audio.' + (fileType.split('/')[1] == 'ogg' ? 'ogg' : 'mp3');
|
||||||
|
actionName = 'sendMessageUploadAudioAction';
|
||||||
|
|
||||||
|
if(options.isVoiceMessage) {
|
||||||
|
attachType = 'voice';
|
||||||
|
pFlags.media_unread = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let attribute: DocumentAttribute.documentAttributeAudio = {
|
||||||
|
_: 'documentAttributeAudio',
|
||||||
|
pFlags: {
|
||||||
|
voice: options.isVoiceMessage
|
||||||
|
},
|
||||||
|
waveform: options.waveform,
|
||||||
|
duration: options.duration || 0
|
||||||
|
};
|
||||||
|
|
||||||
|
attributes.push(attribute);
|
||||||
|
} else if(!options.isMedia) {
|
||||||
attachType = 'document';
|
attachType = 'document';
|
||||||
apiFileName = 'document.' + fileType.split('/')[1];
|
apiFileName = 'document.' + fileType.split('/')[1];
|
||||||
actionName = 'sendMessageUploadDocumentAction';
|
actionName = 'sendMessageUploadDocumentAction';
|
||||||
} else if(isDocument) { // maybe it's a sticker or gif
|
|
||||||
attachType = 'document';
|
|
||||||
apiFileName = '';
|
|
||||||
} else if(isPhoto) {
|
} else if(isPhoto) {
|
||||||
attachType = 'photo';
|
attachType = 'photo';
|
||||||
apiFileName = 'photo.' + fileType.split('/')[1];
|
apiFileName = 'photo.' + fileType.split('/')[1];
|
||||||
actionName = 'sendMessageUploadPhotoAction';
|
actionName = 'sendMessageUploadPhotoAction';
|
||||||
|
|
||||||
let photo: MyPhoto = {
|
photo = {
|
||||||
_: 'photo',
|
_: 'photo',
|
||||||
id: '' + messageID,
|
id: '' + messageID,
|
||||||
sizes: [{
|
sizes: [{
|
||||||
@ -646,30 +669,6 @@ export class AppMessagesManager {
|
|||||||
photo.url = options.objectURL || '';
|
photo.url = options.objectURL || '';
|
||||||
|
|
||||||
appPhotosManager.savePhoto(photo);
|
appPhotosManager.savePhoto(photo);
|
||||||
} else if(fileType.indexOf('audio/') === 0 || ['video/ogg'].indexOf(fileType) >= 0) {
|
|
||||||
attachType = 'audio';
|
|
||||||
apiFileName = 'audio.' + (fileType.split('/')[1] == 'ogg' ? 'ogg' : 'mp3');
|
|
||||||
actionName = 'sendMessageUploadAudioAction';
|
|
||||||
|
|
||||||
let flags = 0;
|
|
||||||
if(options.isVoiceMessage) {
|
|
||||||
flags |= 1 << 10;
|
|
||||||
flags |= 1 << 2;
|
|
||||||
attachType = 'voice';
|
|
||||||
pFlags.media_unread = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let attribute: DocumentAttribute.documentAttributeAudio = {
|
|
||||||
_: 'documentAttributeAudio',
|
|
||||||
flags: flags,
|
|
||||||
pFlags: { // that's only for client, not going to telegram
|
|
||||||
voice: options.isVoiceMessage || undefined
|
|
||||||
},
|
|
||||||
waveform: options.waveform,
|
|
||||||
duration: options.duration || 0
|
|
||||||
};
|
|
||||||
|
|
||||||
attributes.push(attribute);
|
|
||||||
} else if(fileType.indexOf('video/') === 0) {
|
} else if(fileType.indexOf('video/') === 0) {
|
||||||
attachType = 'video';
|
attachType = 'video';
|
||||||
apiFileName = 'video.mp4';
|
apiFileName = 'video.mp4';
|
||||||
@ -677,9 +676,8 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
let videoAttribute: DocumentAttribute.documentAttributeVideo = {
|
let videoAttribute: DocumentAttribute.documentAttributeVideo = {
|
||||||
_: 'documentAttributeVideo',
|
_: 'documentAttributeVideo',
|
||||||
pFlags: { // that's only for client, not going to telegram
|
pFlags: {
|
||||||
supports_streaming: true,
|
round_message: options.isRoundMessage
|
||||||
round_message: options.isRoundMessage || undefined
|
|
||||||
},
|
},
|
||||||
duration: options.duration,
|
duration: options.duration,
|
||||||
w: options.width,
|
w: options.width,
|
||||||
@ -697,7 +695,7 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
if(['document', 'video', 'audio', 'voice'].indexOf(attachType) !== -1 && !isDocument) {
|
if(['document', 'video', 'audio', 'voice'].indexOf(attachType) !== -1 && !isDocument) {
|
||||||
const thumbs: PhotoSize[] = [];
|
const thumbs: PhotoSize[] = [];
|
||||||
const doc: MyDocument = {
|
document = {
|
||||||
_: 'document',
|
_: 'document',
|
||||||
id: '' + messageID,
|
id: '' + messageID,
|
||||||
duration: options.duration,
|
duration: options.duration,
|
||||||
@ -709,10 +707,10 @@ export class AppMessagesManager {
|
|||||||
size: file.size
|
size: file.size
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
defineNotNumerableProperties(doc, ['downloaded', 'url']);
|
defineNotNumerableProperties(document, ['downloaded', 'url']);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
doc.downloaded = file.size;
|
document.downloaded = file.size;
|
||||||
doc.url = options.objectURL || '';
|
document.url = options.objectURL || '';
|
||||||
|
|
||||||
if(isPhoto) {
|
if(isPhoto) {
|
||||||
attributes.push({
|
attributes.push({
|
||||||
@ -732,42 +730,36 @@ export class AppMessagesManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
appDocsManager.saveDoc(doc);
|
appDocsManager.saveDoc(document);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log('AMM: sendFile', attachType, apiFileName, file.type, options);
|
this.log('AMM: sendFile', attachType, apiFileName, file.type, options);
|
||||||
|
|
||||||
var fromID = appUsersManager.getSelf().id;
|
let fromID = appUsersManager.getSelf().id;
|
||||||
if(peerID != fromID) {
|
if(peerID != fromID) {
|
||||||
flags |= 2;
|
|
||||||
pFlags.out = true;
|
pFlags.out = true;
|
||||||
|
|
||||||
if(!isChannel && !appUsersManager.isBot(peerID)) {
|
if(!isChannel && !appUsersManager.isBot(peerID)) {
|
||||||
flags |= 1;
|
|
||||||
pFlags.unread = true;
|
pFlags.unread = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(replyToMsgID) {
|
|
||||||
flags |= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(asChannel) {
|
if(asChannel) {
|
||||||
fromID = 0;
|
fromID = 0;
|
||||||
pFlags.post = true;
|
pFlags.post = true;
|
||||||
} else {
|
|
||||||
flags |= 256;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const preloader = new ProgressivePreloader(null, true, false, 'prepend');
|
const preloader = new ProgressivePreloader(null, true, false, 'prepend');
|
||||||
|
|
||||||
const media = {
|
const media = {
|
||||||
_: 'messageMediaPending',
|
_: 'messageMediaPending',
|
||||||
type: attachType,
|
type: options.isGroupedItem && options.isMedia ? 'album' : attachType,
|
||||||
file_name: fileName || apiFileName,
|
file_name: fileName || apiFileName,
|
||||||
size: file.size,
|
size: file.size,
|
||||||
file: file,
|
file,
|
||||||
preloader: preloader,
|
preloader,
|
||||||
|
photo,
|
||||||
|
document,
|
||||||
w: options.width,
|
w: options.width,
|
||||||
h: options.height,
|
h: options.height,
|
||||||
url: options.objectURL
|
url: options.objectURL
|
||||||
@ -778,8 +770,8 @@ export class AppMessagesManager {
|
|||||||
id: messageID,
|
id: messageID,
|
||||||
from_id: appPeersManager.getOutputPeer(fromID),
|
from_id: appPeersManager.getOutputPeer(fromID),
|
||||||
peer_id: appPeersManager.getOutputPeer(peerID),
|
peer_id: appPeersManager.getOutputPeer(peerID),
|
||||||
pFlags: pFlags,
|
pFlags,
|
||||||
date: date,
|
date,
|
||||||
message: caption,
|
message: caption,
|
||||||
media: isDocument ? {
|
media: isDocument ? {
|
||||||
_: 'messageMediaDocument',
|
_: 'messageMediaDocument',
|
||||||
@ -805,59 +797,22 @@ export class AppMessagesManager {
|
|||||||
let uploaded = false,
|
let uploaded = false,
|
||||||
uploadPromise: ReturnType<ApiFileManager['uploadFile']> = null;
|
uploadPromise: ReturnType<ApiFileManager['uploadFile']> = null;
|
||||||
|
|
||||||
const invoke = (flags: number, inputMedia: any) => {
|
const sentDeferred = deferredPromise<InputMedia>();
|
||||||
this.setTyping(peerID, 'sendMessageCancelAction');
|
|
||||||
|
|
||||||
return apiManager.invokeApi('messages.sendMedia', {
|
|
||||||
flags: flags,
|
|
||||||
background: options.background || undefined,
|
|
||||||
clear_draft: true,
|
|
||||||
peer: appPeersManager.getInputPeerByID(peerID),
|
|
||||||
media: inputMedia,
|
|
||||||
message: caption,
|
|
||||||
random_id: randomIDS,
|
|
||||||
reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID)
|
|
||||||
}).then((updates) => {
|
|
||||||
apiUpdatesManager.processUpdateMessage(updates);
|
|
||||||
}, (error) => {
|
|
||||||
if(attachType == 'photo' &&
|
|
||||||
error.code == 400 &&
|
|
||||||
(error.type == 'PHOTO_INVALID_DIMENSIONS' ||
|
|
||||||
error.type == 'PHOTO_SAVE_FILE_INVALID')) {
|
|
||||||
error.handled = true
|
|
||||||
attachType = 'document'
|
|
||||||
message.send();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleError(true);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
message.send = () => {
|
message.send = () => {
|
||||||
let flags = 0;
|
|
||||||
if(replyToMsgID) {
|
|
||||||
flags |= 1;
|
|
||||||
}
|
|
||||||
if(options.background) {
|
|
||||||
flags |= 64;
|
|
||||||
}
|
|
||||||
flags |= 128; // clear_draft
|
|
||||||
|
|
||||||
if(isDocument) {
|
if(isDocument) {
|
||||||
const {id, access_hash, file_reference} = file as MyDocument;
|
const {id, access_hash, file_reference} = file as MyDocument;
|
||||||
|
|
||||||
const inputMedia = {
|
const inputMedia: InputMedia = {
|
||||||
_: 'inputMediaDocument',
|
_: 'inputMediaDocument',
|
||||||
id: {
|
id: {
|
||||||
_: 'inputDocument',
|
_: 'inputDocument',
|
||||||
id: id,
|
id,
|
||||||
access_hash: access_hash,
|
access_hash,
|
||||||
file_reference: file_reference
|
file_reference
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
invoke(flags, inputMedia);
|
sentDeferred.resolve(inputMedia);
|
||||||
} else if(file instanceof File || file instanceof Blob) {
|
} else if(file instanceof File || file instanceof Blob) {
|
||||||
const deferred = deferredPromise<void>();
|
const deferred = deferredPromise<void>();
|
||||||
|
|
||||||
@ -873,7 +828,7 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
inputFile.name = apiFileName;
|
inputFile.name = apiFileName;
|
||||||
uploaded = true;
|
uploaded = true;
|
||||||
var inputMedia;
|
let inputMedia: InputMedia;
|
||||||
switch(attachType) {
|
switch(attachType) {
|
||||||
case 'photo':
|
case 'photo':
|
||||||
inputMedia = {
|
inputMedia = {
|
||||||
@ -887,11 +842,11 @@ export class AppMessagesManager {
|
|||||||
_: 'inputMediaUploadedDocument',
|
_: 'inputMediaUploadedDocument',
|
||||||
file: inputFile,
|
file: inputFile,
|
||||||
mime_type: fileType,
|
mime_type: fileType,
|
||||||
attributes: attributes
|
attributes
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
invoke(flags, inputMedia);
|
sentDeferred.resolve(inputMedia);
|
||||||
}, (/* error */) => {
|
}, (/* error */) => {
|
||||||
toggleError(true);
|
toggleError(true);
|
||||||
});
|
});
|
||||||
@ -907,6 +862,7 @@ export class AppMessagesManager {
|
|||||||
this.log('cancelling upload', media);
|
this.log('cancelling upload', media);
|
||||||
|
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
|
sentDeferred.reject(err);
|
||||||
this.cancelPendingMessage(randomIDS);
|
this.cancelPendingMessage(randomIDS);
|
||||||
this.setTyping(peerID, 'sendMessageCancelAction');
|
this.setTyping(peerID, 'sendMessageCancelAction');
|
||||||
}
|
}
|
||||||
@ -917,19 +873,52 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
this.sendFilePromise = deferred;
|
this.sendFilePromise = deferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return sentDeferred;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.saveMessages([message]);
|
|
||||||
historyStorage.pending.unshift(messageID);
|
historyStorage.pending.unshift(messageID);
|
||||||
rootScope.broadcast('history_append', {peerID, messageID, my: true});
|
|
||||||
|
|
||||||
setTimeout(message.send.bind(this), 0);
|
|
||||||
|
|
||||||
this.pendingByRandomID[randomIDS] = [peerID, messageID];
|
this.pendingByRandomID[randomIDS] = [peerID, messageID];
|
||||||
|
|
||||||
|
if(!options.isGroupedItem) {
|
||||||
|
this.saveMessages([message]);
|
||||||
|
rootScope.broadcast('history_append', {peerID, messageID, my: true});
|
||||||
|
setTimeout(message.send, 0);
|
||||||
|
sentDeferred.then(inputMedia => {
|
||||||
|
this.setTyping(peerID, 'sendMessageCancelAction');
|
||||||
|
|
||||||
|
return apiManager.invokeApi('messages.sendMedia', {
|
||||||
|
background: options.background,
|
||||||
|
clear_draft: true,
|
||||||
|
peer: appPeersManager.getInputPeerByID(peerID),
|
||||||
|
media: inputMedia,
|
||||||
|
message: caption,
|
||||||
|
random_id: randomIDS,
|
||||||
|
reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID)
|
||||||
|
}).then((updates) => {
|
||||||
|
apiUpdatesManager.processUpdateMessage(updates);
|
||||||
|
}, (error) => {
|
||||||
|
if(attachType == 'photo' &&
|
||||||
|
error.code == 400 &&
|
||||||
|
(error.type == 'PHOTO_INVALID_DIMENSIONS' ||
|
||||||
|
error.type == 'PHOTO_SAVE_FILE_INVALID')) {
|
||||||
|
error.handled = true;
|
||||||
|
attachType = 'document';
|
||||||
|
message.send();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleError(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {message, promise: sentDeferred};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendAlbum(peerID: number, files: File[], options: Partial<{
|
public async sendAlbum(peerID: number, files: File[], options: Partial<{
|
||||||
entities: any[],
|
isMedia: true,
|
||||||
|
entities: MessageEntity[],
|
||||||
replyToMsgID: number,
|
replyToMsgID: number,
|
||||||
caption: string,
|
caption: string,
|
||||||
sendFileDetails: Partial<{
|
sendFileDetails: Partial<{
|
||||||
@ -939,146 +928,50 @@ export class AppMessagesManager {
|
|||||||
objectURL: string,
|
objectURL: string,
|
||||||
}>[]
|
}>[]
|
||||||
}> = {}) {
|
}> = {}) {
|
||||||
|
if(files.length === 1) {
|
||||||
|
return this.sendFile(peerID, files[0], {...options, ...options.sendFileDetails[0]});
|
||||||
|
}
|
||||||
|
|
||||||
peerID = appPeersManager.getPeerMigratedTo(peerID) || peerID;
|
peerID = appPeersManager.getPeerMigratedTo(peerID) || peerID;
|
||||||
let groupID: number;
|
const replyToMsgID = options.replyToMsgID;
|
||||||
let historyStorage = this.historiesStorage[peerID] ?? (this.historiesStorage[peerID] = {count: null, history: [], pending: []});
|
|
||||||
let flags = 0;
|
|
||||||
let pFlags: any = {};
|
|
||||||
let replyToMsgID = options.replyToMsgID;
|
|
||||||
let isChannel = appPeersManager.isChannel(peerID);
|
|
||||||
let isMegagroup = isChannel && appPeersManager.isMegagroup(peerID);
|
|
||||||
let asChannel = isChannel && !isMegagroup ? true : false;
|
|
||||||
|
|
||||||
let caption = options.caption || '';
|
let caption = options.caption || '';
|
||||||
|
let entities: MessageEntity[];
|
||||||
let date = tsNow(true) + serverTimeManager.serverTimeOffset;
|
|
||||||
|
|
||||||
if(caption) {
|
if(caption) {
|
||||||
let entities = options.entities || [];
|
entities = options.entities || [];
|
||||||
caption = RichTextProcessor.parseMarkdown(caption, entities);
|
caption = RichTextProcessor.parseMarkdown(caption, entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log('AMM: sendAlbum', files, options);
|
this.log('AMM: sendAlbum', files, options);
|
||||||
|
|
||||||
let fromID = appUsersManager.getSelf().id;
|
const messages = files.map((file, idx) => {
|
||||||
if(peerID != fromID) {
|
const details = options.sendFileDetails[idx];
|
||||||
pFlags.out = true;
|
const o: any = {
|
||||||
|
isGroupedItem: true,
|
||||||
if(!isChannel && !appUsersManager.isBot(peerID)) {
|
isMedia: options.isMedia,
|
||||||
pFlags.unread = true;
|
...details
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(replyToMsgID) {
|
|
||||||
flags |= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(asChannel) {
|
|
||||||
fromID = 0;
|
|
||||||
pFlags.post = true;
|
|
||||||
} else {
|
|
||||||
flags |= 128; // clear_draft
|
|
||||||
}
|
|
||||||
|
|
||||||
let ids = files.map(() => this.tempID--).reverse();
|
|
||||||
groupID = ids[ids.length - 1];
|
|
||||||
let messages = files.map((file, idx) => {
|
|
||||||
//let messageID = this.tempID--;
|
|
||||||
//if(!groupID) groupID = messageID;
|
|
||||||
let messageID = ids[idx];
|
|
||||||
let randomIDS = randomLong();
|
|
||||||
let preloader = new ProgressivePreloader(null, true, false, 'prepend');
|
|
||||||
|
|
||||||
let details = options.sendFileDetails[idx];
|
|
||||||
|
|
||||||
let media = {
|
|
||||||
_: 'messageMediaPending',
|
|
||||||
type: 'album',
|
|
||||||
preloader: preloader,
|
|
||||||
document: undefined as any,
|
|
||||||
photo: undefined as any
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if(file.type.indexOf('video/') === 0) {
|
if(idx === 0) {
|
||||||
let videoAttribute: DocumentAttribute.documentAttributeVideo = {
|
o.caption = caption;
|
||||||
_: 'documentAttributeVideo',
|
o.entities = entities;
|
||||||
pFlags: { // that's only for client, not going to telegram
|
o.replyToMsgID = replyToMsgID;
|
||||||
supports_streaming: true
|
|
||||||
},
|
|
||||||
duration: details.duration,
|
|
||||||
w: details.width,
|
|
||||||
h: details.height
|
|
||||||
};
|
|
||||||
|
|
||||||
let doc: MyDocument = {
|
|
||||||
_: 'document',
|
|
||||||
id: '' + messageID,
|
|
||||||
attributes: [videoAttribute],
|
|
||||||
thumbs: [],
|
|
||||||
mime_type: file.type,
|
|
||||||
size: file.size
|
|
||||||
} as any;
|
|
||||||
|
|
||||||
defineNotNumerableProperties(doc, ['downloaded', 'url']);
|
|
||||||
// @ts-ignore
|
|
||||||
doc.downloaded = file.size;
|
|
||||||
doc.url = details.objectURL || '';
|
|
||||||
|
|
||||||
appDocsManager.saveDoc(doc);
|
|
||||||
media.document = doc;
|
|
||||||
} else {
|
|
||||||
let photo: any = {
|
|
||||||
_: 'photo',
|
|
||||||
id: '' + messageID,
|
|
||||||
sizes: [{
|
|
||||||
_: 'photoSize',
|
|
||||||
w: details.width,
|
|
||||||
h: details.height,
|
|
||||||
type: 'm',
|
|
||||||
size: file.size
|
|
||||||
} as PhotoSize],
|
|
||||||
w: details.width,
|
|
||||||
h: details.height
|
|
||||||
};
|
|
||||||
|
|
||||||
defineNotNumerableProperties(photo, ['downloaded', 'url']);
|
|
||||||
// @ts-ignore
|
|
||||||
photo.downloaded = file.size;
|
|
||||||
photo.url = details.objectURL || '';
|
|
||||||
|
|
||||||
appPhotosManager.savePhoto(photo);
|
|
||||||
media.photo = photo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let message = {
|
return this.sendFile(peerID, file, o).message;
|
||||||
_: 'message',
|
|
||||||
id: messageID,
|
|
||||||
from_id: appPeersManager.getOutputPeer(fromID),
|
|
||||||
grouped_id: groupID,
|
|
||||||
peer_id: appPeersManager.getOutputPeer(peerID),
|
|
||||||
pFlags: pFlags,
|
|
||||||
date: date,
|
|
||||||
message: caption,
|
|
||||||
media: media,
|
|
||||||
random_id: randomIDS,
|
|
||||||
reply_to: {reply_to_msg_id: replyToMsgID},
|
|
||||||
views: asChannel && 1,
|
|
||||||
pending: true,
|
|
||||||
error: false
|
|
||||||
};
|
|
||||||
|
|
||||||
this.saveMessages([message]);
|
|
||||||
historyStorage.pending.unshift(messageID);
|
|
||||||
//rootScope.$broadcast('history_append', {peerID: peerID, messageID: messageID, my: true});
|
|
||||||
|
|
||||||
this.pendingByRandomID[randomIDS] = [peerID, messageID];
|
|
||||||
|
|
||||||
return message;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
rootScope.broadcast('history_append', {peerID, messageID: messages[messages.length - 1].id, my: true});
|
const groupID = messages[0].id;
|
||||||
|
messages.forEach(message => {
|
||||||
|
message.grouped_id = groupID;
|
||||||
|
});
|
||||||
|
this.saveMessages(messages);
|
||||||
|
|
||||||
let toggleError = (message: any, on: boolean) => {
|
rootScope.broadcast('history_append', {peerID, messageID: groupID, my: true});
|
||||||
|
|
||||||
|
//return;
|
||||||
|
|
||||||
|
const toggleError = (message: any, on: boolean) => {
|
||||||
if(on) {
|
if(on) {
|
||||||
message.error = true;
|
message.error = true;
|
||||||
} else {
|
} else {
|
||||||
@ -1088,15 +981,11 @@ export class AppMessagesManager {
|
|||||||
rootScope.broadcast('messages_pending');
|
rootScope.broadcast('messages_pending');
|
||||||
};
|
};
|
||||||
|
|
||||||
let uploaded = false,
|
const inputPeer = appPeersManager.getInputPeerByID(peerID);
|
||||||
uploadPromise: ReturnType<ApiFileManager['uploadFile']> = null;
|
const invoke = (multiMedia: any[]) => {
|
||||||
|
|
||||||
let inputPeer = appPeersManager.getInputPeerByID(peerID);
|
|
||||||
let invoke = (multiMedia: any[]) => {
|
|
||||||
this.setTyping(peerID, 'sendMessageCancelAction');
|
this.setTyping(peerID, 'sendMessageCancelAction');
|
||||||
|
|
||||||
return apiManager.invokeApi('messages.sendMultiMedia', {
|
return apiManager.invokeApi('messages.sendMultiMedia', {
|
||||||
flags: flags,
|
|
||||||
peer: inputPeer,
|
peer: inputPeer,
|
||||||
multi_media: multiMedia,
|
multi_media: multiMedia,
|
||||||
reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID)
|
reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID)
|
||||||
@ -1107,114 +996,42 @@ export class AppMessagesManager {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
let inputs: any[] = [];
|
const inputs: InputSingleMedia[] = [];
|
||||||
for(let i = 0, length = files.length; i < length; ++i) {
|
for(const message of messages) {
|
||||||
const file = files[i];
|
const inputMedia: InputMedia = await message.send();
|
||||||
const message = messages[i];
|
this.log('sendAlbum uploaded item:', inputMedia);
|
||||||
const media = message.media;
|
|
||||||
const preloader = media.preloader;
|
|
||||||
const actionName = file.type.indexOf('video/') === 0 ? 'sendMessageUploadVideoAction' : 'sendMessageUploadPhotoAction';
|
|
||||||
const deferred = deferredPromise<void>();
|
|
||||||
let canceled = false;
|
|
||||||
|
|
||||||
let apiFileName: string;
|
|
||||||
if(file.type.indexOf('video/') === 0) {
|
|
||||||
apiFileName = 'video.mp4';
|
|
||||||
} else {
|
|
||||||
apiFileName = 'photo.' + file.type.split('/')[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.sendFilePromise;
|
|
||||||
this.sendFilePromise = deferred;
|
|
||||||
|
|
||||||
if(!uploaded || message.error) {
|
|
||||||
uploaded = false;
|
|
||||||
uploadPromise = appDownloadManager.upload(file);
|
|
||||||
preloader.attachPromise(uploadPromise);
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadPromise.addNotifyListener((progress: {done: number, total: number}) => {
|
|
||||||
this.log('upload progress', progress);
|
|
||||||
const percents = Math.max(1, Math.floor(100 * progress.done / progress.total));
|
|
||||||
this.setTyping(peerID, {_: actionName, progress: percents | 0});
|
|
||||||
});
|
|
||||||
|
|
||||||
uploadPromise.catch(err => {
|
|
||||||
if(err.name === 'AbortError' && !uploaded) {
|
|
||||||
this.log('cancelling upload item', media);
|
|
||||||
canceled = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await uploadPromise.then((inputFile) => {
|
|
||||||
this.log('appMessagesManager: sendAlbum file uploaded:', inputFile);
|
|
||||||
|
|
||||||
if(canceled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inputFile.name = apiFileName;
|
|
||||||
|
|
||||||
|
await apiManager.invokeApi('messages.uploadMedia', {
|
||||||
|
peer: inputPeer,
|
||||||
|
media: inputMedia
|
||||||
|
}).then(messageMedia => {
|
||||||
let inputMedia: any;
|
let inputMedia: any;
|
||||||
let details = options.sendFileDetails[i];
|
if(messageMedia._ == 'messageMediaPhoto') {
|
||||||
if(details.duration) {
|
const photo = appPhotosManager.savePhoto(messageMedia.photo);
|
||||||
inputMedia = {
|
inputMedia = appPhotosManager.getInput(photo);
|
||||||
_: 'inputMediaUploadedDocument',
|
} else if(messageMedia._ == 'messageMediaDocument') {
|
||||||
file: inputFile,
|
const doc = appDocsManager.saveDoc(messageMedia.document);
|
||||||
mime_type: file.type,
|
inputMedia = appDocsManager.getMediaInput(doc);
|
||||||
attributes: [{
|
|
||||||
_: 'documentAttributeVideo',
|
|
||||||
supports_streaming: true,
|
|
||||||
duration: details.duration,
|
|
||||||
w: details.width,
|
|
||||||
h: details.height
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
inputMedia = {
|
|
||||||
_: 'inputMediaUploadedPhoto',
|
|
||||||
file: inputFile
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiManager.invokeApi('messages.uploadMedia', {
|
inputs.push({
|
||||||
peer: inputPeer,
|
_: 'inputSingleMedia',
|
||||||
media: inputMedia
|
media: inputMedia,
|
||||||
}).then(messageMedia => {
|
random_id: message.random_id,
|
||||||
if(canceled) {
|
message: caption,
|
||||||
return;
|
entities
|
||||||
}
|
|
||||||
|
|
||||||
let inputMedia: any;
|
|
||||||
if(messageMedia._ == 'messageMediaPhoto') {
|
|
||||||
const photo = appPhotosManager.savePhoto(messageMedia.photo);
|
|
||||||
inputMedia = appPhotosManager.getInput(photo);
|
|
||||||
} else if(messageMedia._ == 'messageMediaDocument') {
|
|
||||||
const doc = appDocsManager.saveDoc(messageMedia.document);
|
|
||||||
inputMedia = appDocsManager.getMediaInput(doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
inputs.push({
|
|
||||||
_: 'inputSingleMedia',
|
|
||||||
media: inputMedia,
|
|
||||||
random_id: message.random_id,
|
|
||||||
message: caption,
|
|
||||||
entities: []
|
|
||||||
});
|
|
||||||
|
|
||||||
caption = ''; // only 1 caption for all inputs
|
|
||||||
}, () => {
|
|
||||||
toggleError(message, true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// * only 1 caption for all inputs
|
||||||
|
if(caption) {
|
||||||
|
caption = '';
|
||||||
|
entities = [];
|
||||||
|
}
|
||||||
}, () => {
|
}, () => {
|
||||||
toggleError(message, true);
|
toggleError(message, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.log('appMessagesManager: sendAlbum uploadPromise.finally!');
|
|
||||||
deferred.resolve();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uploaded = true;
|
|
||||||
invoke(inputs);
|
invoke(inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
/* max-height: 425px; */
|
/* max-height: 425px; */
|
||||||
|
|
||||||
#{$parent}-photo {
|
#{$parent}-photo {
|
||||||
max-height: 320px;
|
//max-height: 320px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
@ -24,6 +24,7 @@
|
|||||||
> div {
|
> div {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,7 +34,7 @@
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
> div {
|
.album-item {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +88,7 @@
|
|||||||
//justify-content: center;
|
//justify-content: center;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
border-radius: $border-radius-medium;
|
border-radius: $border-radius-medium;
|
||||||
|
user-select: none;
|
||||||
/* align-items: center; */
|
/* align-items: center; */
|
||||||
|
|
||||||
.document {
|
.document {
|
||||||
@ -152,4 +154,19 @@
|
|||||||
.popup-header {
|
.popup-header {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkbox-field {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-album, .popup-container:not(.is-album) .popup-item-media {
|
||||||
|
position: relative;
|
||||||
|
border-radius: inherit;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-album + .popup-album, .popup-container:not(.is-album) .popup-item-media + .popup-item-media {
|
||||||
|
margin-top: .5rem;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user