Open documents in media viewer
This commit is contained in:
parent
ab454a5fa2
commit
728c4932ae
@ -11,7 +11,7 @@ import { isMobileSafari, isSafari } from "../helpers/userAgent";
|
||||
import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager";
|
||||
import appImManager from "../lib/appManagers/appImManager";
|
||||
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||
import appPhotosManager from "../lib/appManagers/appPhotosManager";
|
||||
import appPhotosManager, { MyPhoto } from "../lib/appManagers/appPhotosManager";
|
||||
import { logger } from "../lib/logger";
|
||||
import VideoPlayer from "../lib/mediaPlayer";
|
||||
import { RichTextProcessor } from "../lib/richtextprocessor";
|
||||
@ -36,7 +36,7 @@ import { Message } from "../layer";
|
||||
import { forEachReverse } from "../helpers/array";
|
||||
import AppSharedMediaTab from "./sidebarRight/tabs/sharedMedia";
|
||||
import findUpClassName from "../helpers/dom/findUpClassName";
|
||||
import renderImageFromUrl from "../helpers/dom/renderImageFromUrl";
|
||||
import renderImageFromUrl, { renderImageFromUrlPromise } from "../helpers/dom/renderImageFromUrl";
|
||||
import getVisibleRect from "../helpers/dom/getVisibleRect";
|
||||
import appDownloadManager from "../lib/appManagers/appDownloadManager";
|
||||
import { cancelEvent } from "../helpers/dom/cancelEvent";
|
||||
@ -48,6 +48,7 @@ import appMessagesIdsManager from "../lib/appManagers/appMessagesIdsManager";
|
||||
import I18n, { i18n } from "../lib/langPack";
|
||||
import { capitalizeFirstLetter } from "../helpers/string";
|
||||
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||
import { doubleRaf, fastRaf } from "../helpers/schedulers";
|
||||
|
||||
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
|
||||
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
|
||||
@ -511,8 +512,15 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
const deferred = this.setMoverAnimationPromise = deferredPromise<void>();
|
||||
const ret = {onAnimationEnd: deferred};
|
||||
|
||||
this.setMoverAnimationPromise.then(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
if(!deferred.isFulfilled && !deferred.isRejected) {
|
||||
deferred.resolve();
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
this.setMoverAnimationPromise.finally(() => {
|
||||
this.setMoverAnimationPromise = null;
|
||||
clearTimeout(timeout);
|
||||
});
|
||||
|
||||
if(!closing) {
|
||||
@ -520,9 +528,11 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
let src: string;
|
||||
|
||||
if(target.tagName === 'DIV' || target.tagName === 'AVATAR-ELEMENT') { // useContainerAsTarget
|
||||
if(target.firstElementChild) {
|
||||
const images = Array.from(target.querySelectorAll('img')) as HTMLImageElement[];
|
||||
const image = images.pop();
|
||||
if(image) {
|
||||
mediaElement = new Image();
|
||||
src = (target.firstElementChild as HTMLImageElement).src;
|
||||
src = image.src;
|
||||
mover.append(mediaElement);
|
||||
}
|
||||
/* mediaElement = new Image();
|
||||
@ -532,8 +542,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
mediaElement = new Image();
|
||||
src = target.src;
|
||||
} else if(target instanceof HTMLVideoElement) {
|
||||
const video = mediaElement = document.createElement('video');
|
||||
video.src = target?.src;
|
||||
mediaElement = document.createElement('video');
|
||||
mediaElement.src = target.src;
|
||||
} else if(target instanceof SVGSVGElement) {
|
||||
const clipId = target.dataset.clipId;
|
||||
const newClipId = clipId + '-mv';
|
||||
@ -605,13 +615,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
}
|
||||
|
||||
if(src) {
|
||||
await new Promise((resolve, reject) => {
|
||||
mediaElement.addEventListener('load', resolve);
|
||||
|
||||
if(src) {
|
||||
mediaElement.src = src;
|
||||
}
|
||||
});
|
||||
await renderImageFromUrlPromise(mediaElement, src);
|
||||
}
|
||||
}/* else if(mediaElement instanceof HTMLVideoElement && mediaElement.firstElementChild && ((mediaElement.firstElementChild as HTMLSourceElement).src || src)) {
|
||||
await new Promise((resolve, reject) => {
|
||||
@ -625,7 +629,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
|
||||
mover.style.display = '';
|
||||
|
||||
window.requestAnimationFrame(() => {
|
||||
fastRaf(() => {
|
||||
mover.classList.add(wasActive ? 'moving' : 'active');
|
||||
});
|
||||
} else {
|
||||
@ -674,7 +678,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
//await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
//await new Promise((resolve) => window.requestAnimationFrame(resolve));
|
||||
// * одного RAF'а недостаточно, иногда анимация с одним не срабатывает (преимущественно на мобильных)
|
||||
await new Promise((resolve) => window.requestAnimationFrame(() => window.requestAnimationFrame(resolve)));
|
||||
await doubleRaf();
|
||||
|
||||
// чтобы проверить установленную позицию - раскомментировать
|
||||
// throw '';
|
||||
@ -779,7 +783,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
else d = generatePathData(9 / scaleX * progress, 0, width/* width - (9 / scaleX * progress) */, height, ..._br);
|
||||
path.setAttributeNS(null, 'd', d);
|
||||
|
||||
if(diff < delay) window.requestAnimationFrame(step);
|
||||
if(diff < delay) fastRaf(step);
|
||||
};
|
||||
|
||||
//window.requestAnimationFrame(step);
|
||||
@ -829,6 +833,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
protected setNewMover() {
|
||||
const newMover = document.createElement('div');
|
||||
newMover.classList.add('media-viewer-mover');
|
||||
newMover.style.display = 'none';
|
||||
|
||||
if(this.content.mover) {
|
||||
const oldMover = this.content.mover;
|
||||
@ -923,7 +928,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
|
||||
this.setAuthorInfo(fromId, timestamp);
|
||||
|
||||
const isVideo = (media as MyDocument).type === 'video' || (media as MyDocument).type === 'gif';
|
||||
const isDocument = media._ === 'document';
|
||||
const isVideo = media.mime_type && ((['video', 'gif'] as MyDocument['type'][]).includes((media as MyDocument).type) || (media as MyDocument).mime_type.indexOf('video/') === 0);
|
||||
|
||||
if(this.isFirstOpen) {
|
||||
//this.targetContainer = targetContainer;
|
||||
@ -1014,7 +1020,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
}
|
||||
const maxHeight = windowH - 120 - padding;
|
||||
let thumbPromise: Promise<any> = Promise.resolve();
|
||||
const size = appPhotosManager.setAttachmentSize(media, container, maxWidth, maxHeight, mediaSizes.isMobile ? false : true).photoSize;
|
||||
const size = appPhotosManager.setAttachmentSize(media, container, maxWidth, maxHeight, mediaSizes.isMobile ? false : true, undefined, media._ === 'document' && media.w && media.h).photoSize;
|
||||
if(useContainerAsTarget) {
|
||||
const cacheContext = appDownloadManager.getCacheContext(media, size.type);
|
||||
let img: HTMLImageElement;
|
||||
@ -1040,7 +1046,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
target = target.querySelector('img, video') || target;
|
||||
} */
|
||||
|
||||
const preloader = media.supportsStreaming ? this.preloaderStreamable : this.preloader;
|
||||
const supportsStreaming = media.supportsStreaming;
|
||||
const preloader = supportsStreaming ? this.preloaderStreamable : this.preloader;
|
||||
|
||||
let setMoverPromise: Promise<void>;
|
||||
if(isVideo) {
|
||||
@ -1072,6 +1079,16 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
video.pause();
|
||||
}
|
||||
});
|
||||
|
||||
video.addEventListener('error', (err) => {
|
||||
if(video.error.code !== 4) {
|
||||
this.log.error("Error " + video.error.code + "; details: " + video.error.message);
|
||||
}
|
||||
|
||||
if(preloader) {
|
||||
preloader.detach();
|
||||
}
|
||||
}, {once: true});
|
||||
|
||||
if(isSafari) {
|
||||
// test stream
|
||||
@ -1107,7 +1124,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
return;
|
||||
}
|
||||
|
||||
const player = new VideoPlayer(video, true, media.supportsStreaming);
|
||||
const player = new VideoPlayer(video, true, supportsStreaming);
|
||||
player.addEventListener('toggleControls', (show) => {
|
||||
this.wholeDiv.classList.toggle('has-video-controls', show);
|
||||
});
|
||||
@ -1118,7 +1135,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
}
|
||||
};
|
||||
|
||||
if(media.supportsStreaming) {
|
||||
if(supportsStreaming) {
|
||||
onAnimationEnd.then(() => {
|
||||
if(video.readyState < video.HAVE_FUTURE_DATA) {
|
||||
preloader.attach(mover, true);
|
||||
@ -1158,9 +1175,9 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
//if(!video.src || media.url !== video.src) {
|
||||
const load = () => {
|
||||
const cacheContext = appDownloadManager.getCacheContext(media);
|
||||
const promise = media.supportsStreaming ? Promise.resolve() : appDocsManager.downloadDoc(media);
|
||||
const promise: Promise<any> = supportsStreaming ? Promise.resolve() : appDocsManager.downloadDoc(media);
|
||||
|
||||
if(!media.supportsStreaming) {
|
||||
if(!supportsStreaming) {
|
||||
onAnimationEnd.then(() => {
|
||||
if(!cacheContext.url) {
|
||||
preloader.attach(mover, true, promise);
|
||||
@ -1168,7 +1185,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
});
|
||||
}
|
||||
|
||||
(promise as Promise<any>).then(async() => {
|
||||
Promise.all([promise, onAnimationEnd]).then(async() => {
|
||||
if(this.tempId !== tempId) {
|
||||
this.log.warn('media viewer changed video');
|
||||
return;
|
||||
@ -1204,7 +1221,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
|
||||
const load = () => {
|
||||
const cacheContext = appDownloadManager.getCacheContext(media, size.type);
|
||||
const cancellablePromise = appPhotosManager.preloadPhoto(media.id, size);
|
||||
const cancellablePromise = isDocument ? appDocsManager.downloadDoc(media) : appPhotosManager.preloadPhoto(media, size);
|
||||
|
||||
onAnimationEnd.then(() => {
|
||||
if(!cacheContext.url) {
|
||||
@ -1247,7 +1264,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
this.updateMediaSource(target, url, 'img');
|
||||
|
||||
if(haveImage) {
|
||||
window.requestAnimationFrame(() => {
|
||||
fastRaf(() => {
|
||||
haveImage.remove();
|
||||
});
|
||||
}
|
||||
@ -1477,12 +1494,16 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
}
|
||||
|
||||
const method: any = older ? value.history.forEach.bind(value.history) : forEachReverse.bind(null, value.history);
|
||||
const isForDocument = this.searchContext.inputFilter === 'inputMessagesFilterDocument';
|
||||
method((message: Message.message) => {
|
||||
const {mid, peerId} = message;
|
||||
const media = this.getMediaFromMessage(message);
|
||||
const media: MyPhoto | MyDocument = appMessagesManager.getMediaFromMessage(message);
|
||||
|
||||
if(!media) return;
|
||||
//if(media._ === 'document' && media.type !== 'video') return;
|
||||
|
||||
if(isForDocument && !AppMediaViewer.isMediaCompatibleForDocumentViewer(media)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const t = {element: null as HTMLElement, mid, peerId};
|
||||
if(older) {
|
||||
@ -1507,12 +1528,6 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
return promise;
|
||||
};
|
||||
|
||||
private getMediaFromMessage(message: any) {
|
||||
return message.action ? message.action.photo : message.media.photo
|
||||
|| message.media.document
|
||||
|| (message.media.webpage && (message.media.webpage.document || message.media.webpage.photo));
|
||||
}
|
||||
|
||||
private setCaption(message: Message.message) {
|
||||
const caption = message.message;
|
||||
let html = '';
|
||||
@ -1548,7 +1563,7 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
|
||||
const mid = message.mid;
|
||||
const fromId = message.fromId;
|
||||
const media = this.getMediaFromMessage(message);
|
||||
const media = appMessagesManager.getMediaFromMessage(message);
|
||||
|
||||
this.buttons.forward.classList.toggle('hide', message._ === 'messageService');
|
||||
|
||||
@ -1559,6 +1574,10 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
public static isMediaCompatibleForDocumentViewer(media: MyPhoto | MyDocument) {
|
||||
return media._ === 'photo' || (['photo', 'video', 'gif'].includes(media.type) || media.mime_type.indexOf('video/') === 0);
|
||||
}
|
||||
}
|
||||
|
||||
type AppMediaViewerAvatarTargetType = {element: HTMLElement, photoId: string};
|
||||
|
@ -216,6 +216,7 @@ function wrapVoiceMessage(audioEl: AudioElement) {
|
||||
});
|
||||
progress.addEventListener('mousedown', (e) => {
|
||||
e.preventDefault();
|
||||
if(e.button !== 1) return;
|
||||
if(!audio.paused) {
|
||||
audio.pause();
|
||||
}
|
||||
|
@ -955,50 +955,75 @@ export default class ChatBubbles {
|
||||
return;
|
||||
}
|
||||
|
||||
const documentDiv = findUpClassName(target, 'document-with-thumb');
|
||||
if((target.tagName === 'IMG' && !target.classList.contains('emoji') && !target.classList.contains('document-thumb'))
|
||||
|| target.classList.contains('album-item')
|
||||
|| isVideoComponentElement
|
||||
|| (target.tagName === 'VIDEO' && !bubble.classList.contains('round'))) {
|
||||
let messageId = +findUpClassName(target, 'album-item')?.dataset.mid || +bubble.dataset.mid;
|
||||
let message = this.chat.getMessage(messageId);
|
||||
|| (target.tagName === 'VIDEO' && !bubble.classList.contains('round'))
|
||||
|| (documentDiv && !documentDiv.querySelector('.preloader-container'))) {
|
||||
const groupedItem = findUpClassName(target, 'album-item') || findUpClassName(target, 'document-container');
|
||||
const messageId = +(groupedItem || bubble).dataset.mid;
|
||||
const message = this.chat.getMessage(messageId);
|
||||
if(!message) {
|
||||
this.log.warn('no message by messageId:', messageId);
|
||||
return;
|
||||
}
|
||||
|
||||
let targets: {element: HTMLElement, mid: number, peerId: number}[] = [];
|
||||
let ids = Object.keys(this.bubbles).map(k => +k).filter(id => {
|
||||
const f = documentDiv ? (media: any) => {
|
||||
return AppMediaViewer.isMediaCompatibleForDocumentViewer(media);
|
||||
} : (media: any) => {
|
||||
return media._ === 'photo' || ['video', 'gif'].includes(media.type);
|
||||
};
|
||||
|
||||
const targets: {element: HTMLElement, mid: number, peerId: number}[] = [];
|
||||
const ids = Object.keys(this.bubbles).map(k => +k).filter(id => {
|
||||
//if(!this.scrollable.visibleElements.find(e => e.element === this.bubbles[id])) return false;
|
||||
|
||||
let message = this.chat.getMessage(id);
|
||||
const message = this.chat.getMessage(id);
|
||||
const media = this.appMessagesManager.getMediaFromMessage(message);
|
||||
|
||||
return message.media && (message.media.photo || (message.media.document && (message.media.document.type === 'video' || message.media.document.type === 'gif')) || (message.media.webpage && (message.media.webpage.document || message.media.webpage.photo)));
|
||||
return media && f(media);
|
||||
}).sort((a, b) => a - b);
|
||||
|
||||
ids.forEach(id => {
|
||||
let withTail = this.bubbles[id].classList.contains('with-media-tail');
|
||||
let str = '.album-item video, .album-item img, .preview video, .preview img, ';
|
||||
if(withTail) {
|
||||
str += '.bubble__media-container';
|
||||
let selector: string;
|
||||
if(documentDiv) {
|
||||
selector = '.document-container';
|
||||
} else {
|
||||
str += '.attachment video, .attachment img';
|
||||
const withTail = this.bubbles[id].classList.contains('with-media-tail');
|
||||
selector = '.album-item video, .album-item img, .preview video, .preview img, ';
|
||||
if(withTail) {
|
||||
selector += '.bubble__media-container';
|
||||
} else {
|
||||
selector += '.attachment video, .attachment img';
|
||||
}
|
||||
}
|
||||
|
||||
const hasAspecter = !!this.bubbles[id].querySelector('.media-container-aspecter');
|
||||
let elements = this.bubbles[id].querySelectorAll(str) as NodeListOf<HTMLElement>;
|
||||
const elements = Array.from(this.bubbles[id].querySelectorAll(selector)) as HTMLElement[];
|
||||
const parents: Set<HTMLElement> = new Set();
|
||||
Array.from(elements).forEach((element: HTMLElement) => {
|
||||
if(hasAspecter && !findUpClassName(element, 'media-container-aspecter')) return;
|
||||
let albumItem = findUpClassName(element, 'album-item');
|
||||
const parent = albumItem || element.parentElement;
|
||||
if(parents.has(parent)) return;
|
||||
parents.add(parent);
|
||||
targets.push({
|
||||
element,
|
||||
mid: +albumItem?.dataset.mid || id,
|
||||
peerId: this.peerId
|
||||
if(documentDiv) {
|
||||
elements.forEach((element) => {
|
||||
targets.push({
|
||||
element: element.querySelector('.document-ico'),
|
||||
mid: +element.dataset.mid,
|
||||
peerId: this.peerId
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
const hasAspecter = !!this.bubbles[id].querySelector('.media-container-aspecter');
|
||||
elements.forEach((element) => {
|
||||
if(hasAspecter && !findUpClassName(element, 'media-container-aspecter')) return;
|
||||
let albumItem = findUpClassName(element, 'album-item');
|
||||
const parent = albumItem || element.parentElement;
|
||||
if(parents.has(parent)) return;
|
||||
parents.add(parent);
|
||||
targets.push({
|
||||
element,
|
||||
mid: albumItem ? +albumItem.dataset.mid : id,
|
||||
peerId: this.peerId
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
targets.sort((a, b) => a.mid - b.mid);
|
||||
@ -1018,7 +1043,7 @@ export default class ChatBubbles {
|
||||
.setSearchContext({
|
||||
threadId: this.chat.threadId,
|
||||
peerId: this.peerId,
|
||||
inputFilter: 'inputMessagesFilterPhotoVideo'
|
||||
inputFilter: documentDiv ? 'inputMessagesFilterDocument' : 'inputMessagesFilterPhotoVideo'
|
||||
})
|
||||
.openMedia(message, targets[idx].element, 0, true, targets.slice(0, idx), targets.slice(idx + 1));
|
||||
|
||||
@ -2760,7 +2785,7 @@ export default class ChatBubbles {
|
||||
</div>`;
|
||||
|
||||
const avatarElem = new AvatarElement();
|
||||
//avatarElem.lazyLoadQueue = this.lazyLoadQueue;
|
||||
avatarElem.lazyLoadQueue = this.lazyLoadQueue;
|
||||
avatarElem.setAttribute('peer', '' + message.media.user_id);
|
||||
avatarElem.classList.add('contact-avatar', 'avatar-54');
|
||||
|
||||
@ -2901,7 +2926,7 @@ export default class ChatBubbles {
|
||||
const needAvatar = this.chat.isAnyGroup() && !isOut;
|
||||
if(needAvatar) {
|
||||
let avatarElem = new AvatarElement();
|
||||
//avatarElem.lazyLoadQueue = this.lazyLoadQueue;
|
||||
avatarElem.lazyLoadQueue = this.lazyLoadQueue;
|
||||
avatarElem.classList.add('user-avatar', 'avatar-40');
|
||||
avatarElem.loadPromises = loadPromises;
|
||||
|
||||
|
@ -283,7 +283,12 @@ export default class ChatContextMenu {
|
||||
}
|
||||
|
||||
const doc: MyDocument = this.message.media?.document;
|
||||
return doc && doc.type && !(['gif', 'photo', 'video', 'sticker'] as MyDocument['type'][]).includes(doc.type);
|
||||
if(!doc) return false;
|
||||
|
||||
let hasTarget = !!isTouchSupported;
|
||||
const isGoodType = !doc.type || !(['gif', 'video', 'sticker'] as MyDocument['type'][]).includes(doc.type);
|
||||
if(isGoodType) hasTarget = hasTarget || !!findUpClassName(this.target, 'document') || !!findUpClassName(this.target, 'audio');
|
||||
return isGoodType && hasTarget;
|
||||
}
|
||||
}, {
|
||||
icon: 'checkretract',
|
||||
|
@ -446,6 +446,15 @@ export const formatDate = (timestamp: number, monthShort = false, withYear = tru
|
||||
return str + ' at ' + date.getHours() + ':' + ('0' + date.getMinutes()).slice(-2);
|
||||
};
|
||||
|
||||
rootScope.addEventListener('download_start', (docId) => {
|
||||
const elements = Array.from(document.querySelectorAll(`.document[data-doc-id="${docId}"]`)) as HTMLElement[];
|
||||
elements.forEach(element => {
|
||||
if(element.querySelector('.preloader-container.manual')) {
|
||||
element.click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showSender, searchContext, loadPromises, noAutoDownload, lazyLoadQueue}: {
|
||||
message: any,
|
||||
withTime?: boolean,
|
||||
@ -569,14 +578,17 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
|
||||
const load = () => {
|
||||
const doc = appDocsManager.getDoc(docDiv.dataset.docId);
|
||||
let download: DownloadBlob;
|
||||
const queueId = appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : undefined;
|
||||
if(doc.type === 'pdf') {
|
||||
download = appDocsManager.downloadDoc(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);
|
||||
download = appDocsManager.downloadDoc(doc, queueId);
|
||||
download.then(() => {
|
||||
const cacheContext = appDownloadManager.getCacheContext(doc);
|
||||
window.open(cacheContext.url);
|
||||
});
|
||||
} else if(doc.type === 'photo' || doc.type === 'video' || doc.mime_type.indexOf('video/') === 0) {
|
||||
download = appDocsManager.downloadDoc(doc, queueId);
|
||||
} else {
|
||||
download = appDocsManager.saveDocFile(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);
|
||||
download = appDocsManager.saveDocFile(doc, queueId);
|
||||
}
|
||||
|
||||
if(downloadDiv) {
|
||||
@ -587,7 +599,11 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
|
||||
return {download};
|
||||
};
|
||||
|
||||
if(!(cacheContext.downloaded && !uploading)) {
|
||||
if(appDocsManager.downloading.has(doc.id)) {
|
||||
downloadDiv = docDiv.querySelector('.document-download');
|
||||
preloader = new ProgressivePreloader();
|
||||
preloader.attach(downloadDiv, false, appDocsManager.downloading.get(doc.id));
|
||||
} else if(!(cacheContext.downloaded && !uploading)) {
|
||||
downloadDiv = docDiv.querySelector('.document-download');
|
||||
preloader = message.media.preloader as ProgressivePreloader;
|
||||
|
||||
|
@ -22,6 +22,7 @@ import blur from '../../helpers/blur';
|
||||
import apiManager from '../mtproto/mtprotoworker';
|
||||
import { MOUNT_CLASS_TO } from '../../config/debug';
|
||||
import { getFullDate } from '../../helpers/date';
|
||||
import rootScope from '../rootScope';
|
||||
|
||||
export type MyDocument = Document.document;
|
||||
|
||||
@ -30,6 +31,7 @@ export type MyDocument = Document.document;
|
||||
export class AppDocsManager {
|
||||
private docs: {[docId: string]: MyDocument} = {};
|
||||
private savingLottiePreview: {[docId: string]: true} = {};
|
||||
public downloading: Map<string, DownloadBlob> = new Map();
|
||||
|
||||
constructor() {
|
||||
apiManager.onServiceWorkerFail = this.onServiceWorkerFail;
|
||||
@ -187,7 +189,7 @@ export class AppDocsManager {
|
||||
}
|
||||
|
||||
if(apiManager.isServiceWorkerOnline()) {
|
||||
if((doc.type === 'gif' && doc.size > 8e6) || doc.type === 'audio' || doc.type === 'video') {
|
||||
if((doc.type === 'gif' && doc.size > 8e6) || doc.type === 'audio' || doc.type === 'video'/* || doc.mime_type.indexOf('video/') === 0 */) {
|
||||
doc.supportsStreaming = true;
|
||||
|
||||
const cacheContext = appDownloadManager.getCacheContext(doc);
|
||||
@ -323,13 +325,17 @@ export class AppDocsManager {
|
||||
|
||||
const downloadOptions = this.getFileDownloadOptions(doc, undefined, queueId, onlyCache);
|
||||
download = appDownloadManager.download(downloadOptions);
|
||||
this.downloading.set(doc.id, download);
|
||||
rootScope.dispatchEvent('download_start', doc.id);
|
||||
|
||||
const cacheContext = appDownloadManager.getCacheContext(doc);
|
||||
const originalPromise = download;
|
||||
originalPromise.then((blob) => {
|
||||
cacheContext.url = URL.createObjectURL(blob);
|
||||
cacheContext.downloaded = blob.size;
|
||||
}, () => {});
|
||||
}, () => {}).finally(() => {
|
||||
this.downloading.delete(doc.id);
|
||||
});
|
||||
|
||||
if(doc.type === 'voice' && !opusDecodeController.isPlaySupported()) {
|
||||
download = originalPromise.then(async(blob) => {
|
||||
|
@ -5219,6 +5219,20 @@ export class AppMessagesManager {
|
||||
appWebPagesManager.deleteWebPageFromPending(oldMessage.media.webpage, oldMessage.mid);
|
||||
}
|
||||
}
|
||||
|
||||
public getMediaFromMessage(message: any) {
|
||||
return message.action ?
|
||||
message.action.photo :
|
||||
message.media && (
|
||||
message.media.photo ||
|
||||
message.media.document || (
|
||||
message.media.webpage && (
|
||||
message.media.webpage.document ||
|
||||
message.media.webpage.photo
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const appMessagesManager = new AppMessagesManager();
|
||||
|
@ -87,7 +87,7 @@ export class AppPhotosManager {
|
||||
return this.photos[photo.id] = photo;
|
||||
}
|
||||
|
||||
public choosePhotoSize(photo: MyPhoto | MyDocument, boxWidth = 0, boxHeight = 0, useBytes = false) {
|
||||
public choosePhotoSize(photo: MyPhoto | MyDocument, boxWidth = 0, boxHeight = 0, useBytes = false, pushDocumentSize = false) {
|
||||
if(window.devicePixelRatio > 1) {
|
||||
boxWidth *= 2;
|
||||
boxHeight *= 2;
|
||||
@ -105,7 +105,17 @@ export class AppPhotosManager {
|
||||
d crop 1280x1280 */
|
||||
|
||||
let bestPhotoSize: PhotoSize = {_: 'photoSizeEmpty', type: ''};
|
||||
const sizes = ((photo as MyPhoto).sizes || (photo as MyDocument).thumbs) as PhotoSize[];
|
||||
let sizes = (photo as MyPhoto).sizes || (photo as MyDocument).thumbs as PhotoSize[];
|
||||
if(pushDocumentSize && sizes && photo._ === 'document') {
|
||||
sizes = sizes.concat({
|
||||
_: 'photoSize',
|
||||
w: (photo as MyDocument).w,
|
||||
h: (photo as MyDocument).h,
|
||||
size: (photo as MyDocument).size,
|
||||
type: undefined
|
||||
});
|
||||
}
|
||||
|
||||
if(sizes?.length) {
|
||||
for(let i = 0, length = sizes.length; i < length; ++i) {
|
||||
const photoSize = sizes[i];
|
||||
@ -214,15 +224,22 @@ export class AppPhotosManager {
|
||||
return {image, loadPromise};
|
||||
}
|
||||
|
||||
public setAttachmentSize(photo: MyPhoto | MyDocument, element: HTMLElement | SVGForeignObjectElement, boxWidth: number, boxHeight: number, noZoom = true, message?: any) {
|
||||
const photoSize = this.choosePhotoSize(photo, boxWidth, boxHeight);
|
||||
public setAttachmentSize(photo: MyPhoto | MyDocument,
|
||||
element: HTMLElement | SVGForeignObjectElement,
|
||||
boxWidth: number,
|
||||
boxHeight: number,
|
||||
noZoom = true,
|
||||
message?: any,
|
||||
pushDocumentSize?: boolean) {
|
||||
const photoSize = this.choosePhotoSize(photo, boxWidth, boxHeight, undefined, pushDocumentSize);
|
||||
//console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);
|
||||
|
||||
let size: MediaSize;
|
||||
if(photo._ === 'document') {
|
||||
size = makeMediaSize(photo.w || 512, photo.h || 512);
|
||||
const isDocument = photo._ === 'document';
|
||||
if(isDocument) {
|
||||
size = makeMediaSize((photo as MyDocument).w || (photoSize as PhotoSize.photoSize).w || 512, (photo as MyDocument).h || (photoSize as PhotoSize.photoSize).h || 512);
|
||||
} else {
|
||||
size = makeMediaSize('w' in photoSize ? photoSize.w : 100, 'h' in photoSize ? photoSize.h : 100);
|
||||
size = makeMediaSize((photoSize as PhotoSize.photoSize).w || 100, (photoSize as PhotoSize.photoSize).h || 100);
|
||||
}
|
||||
|
||||
let boxSize = makeMediaSize(boxWidth, boxHeight);
|
||||
@ -231,7 +248,7 @@ export class AppPhotosManager {
|
||||
|
||||
let isFit = true;
|
||||
|
||||
if(photo._ === 'photo' || ['video', 'gif'].includes(photo.type)) {
|
||||
if(!isDocument || ['video', 'gif'].includes((photo as MyDocument).type)) {
|
||||
if(boxSize.width < 200 && boxSize.height < 200) { // make at least one side this big
|
||||
boxSize = size = size.aspectCovered(makeMediaSize(200, 200));
|
||||
}
|
||||
@ -249,7 +266,7 @@ export class AppPhotosManager {
|
||||
}
|
||||
}
|
||||
|
||||
if(isFit && boxSize.width < 120) { // if image is too narrow
|
||||
if(isFit && boxSize.width < 120 && message) { // if image is too narrow
|
||||
boxSize = makeMediaSize(120, boxSize.height);
|
||||
isFit = false;
|
||||
}
|
||||
|
@ -90,41 +90,43 @@ export type BroadcastEvents = {
|
||||
//'channel_settings': {channelId: number},
|
||||
'webpage_updated': {id: string, msgs: {peerId: number, mid: number, isScheduled: boolean}[]},
|
||||
|
||||
'download_progress': any,
|
||||
'connection_status_change': ConnectionStatusChange,
|
||||
'settings_updated': {key: string, value: any},
|
||||
'draft_updated': {peerId: number, threadId: number, draft: MyDraftMessage | undefined, force?: boolean},
|
||||
|
||||
|
||||
'event-heavy-animation-start': void,
|
||||
'event-heavy-animation-end': void,
|
||||
|
||||
|
||||
'im_mount': void,
|
||||
'im_tab_change': number,
|
||||
|
||||
|
||||
'idle': boolean,
|
||||
|
||||
|
||||
'overlay_toggle': boolean,
|
||||
|
||||
|
||||
'background_change': void,
|
||||
|
||||
|
||||
'privacy_update': Update.updatePrivacy,
|
||||
|
||||
|
||||
'notify_settings': Update.updateNotifySettings,
|
||||
'notify_peer_type_settings': {key: Exclude<NotifyPeer['_'], 'notifyPeer'>, settings: PeerNotifySettings},
|
||||
|
||||
|
||||
'language_change': string,
|
||||
|
||||
'theme_change': void,
|
||||
|
||||
|
||||
'instance_activated': void,
|
||||
'instance_deactivated': void,
|
||||
|
||||
|
||||
'push_notification_click': PushNotificationObject,
|
||||
'push_init': PushSubscriptionNotify,
|
||||
'push_subscribe': PushSubscriptionNotify,
|
||||
'push_unsubscribe': PushSubscriptionNotify,
|
||||
|
||||
'emoji_recent': string
|
||||
|
||||
'emoji_recent': string,
|
||||
|
||||
'download_start': string,
|
||||
'download_progress': any,
|
||||
};
|
||||
|
||||
export class RootScope extends EventListenerBase<{
|
||||
|
Loading…
Reference in New Issue
Block a user