tweb/src/components/appMediaViewer.ts

278 lines
9.2 KiB
TypeScript
Raw Normal View History

2021-04-08 15:52:31 +02:00
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
2021-10-05 22:40:07 +02:00
import MEDIA_MIME_TYPES_SUPPORTED from "../environment/mediaMimeTypesSupport";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import { attachClickEvent } from "../helpers/dom/clickEvent";
import setInnerHTML from "../helpers/dom/setInnerHTML";
import mediaSizes from "../helpers/mediaSizes";
2021-10-05 22:40:07 +02:00
import SearchListLoader from "../helpers/searchListLoader";
import { Message } from "../layer";
import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager";
import appImManager from "../lib/appManagers/appImManager";
import appMessagesManager from "../lib/appManagers/appMessagesManager";
2021-08-18 16:48:13 +02:00
import appPhotosManager, { MyPhoto } from "../lib/appManagers/appPhotosManager";
2021-10-05 22:40:07 +02:00
import RichTextProcessor from "../lib/richtextprocessor";
import { MediaSearchContext } from "./appMediaPlaybackController";
import AppMediaViewerBase, { MEDIA_VIEWER_CLASSNAME } from "./appMediaViewerBase";
import { ButtonMenuItemOptions } from "./buttonMenu";
2021-10-05 22:40:07 +02:00
import PopupDeleteMessages from "./popups/deleteMessages";
import PopupForward from "./popups/forward";
2020-10-31 19:45:49 +01:00
import Scrollable from "./scrollable";
2021-07-19 15:51:53 +02:00
import appSidebarRight from "./sidebarRight";
2021-10-05 22:40:07 +02:00
import AppSharedMediaTab from "./sidebarRight/tabs/sharedMedia";
2020-02-06 16:43:07 +01:00
type AppMediaViewerTargetType = {
element: HTMLElement,
2020-12-25 13:53:20 +01:00
mid: number,
2021-10-21 15:16:43 +02:00
peerId: PeerId
};
export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delete' | 'forward', AppMediaViewerTargetType> {
2021-08-20 16:49:32 +02:00
protected btnMenuDelete: HTMLElement;
protected listLoader: SearchListLoader<AppMediaViewerTargetType>;
2021-09-23 17:22:30 +02:00
get searchContext() {
return this.listLoader.searchContext;
2021-09-23 17:22:30 +02:00
}
2021-09-23 17:22:30 +02:00
constructor() {
super(new SearchListLoader({
processItem: (item) => {
const isForDocument = this.searchContext.inputFilter._ === 'inputMessagesFilterDocument';
const {mid, peerId} = item;
const media: MyPhoto | MyDocument = appMessagesManager.getMediaFromMessage(item);
if(!media) return;
if(isForDocument && !AppMediaViewer.isMediaCompatibleForDocumentViewer(media)) {
return;
}
return {element: null as HTMLElement, mid, peerId};
}
2021-09-23 17:22:30 +02:00
}), ['delete', 'forward']);
2021-10-05 22:40:07 +02:00
this.listLoader.onEmptied = () => {
this.close();
};
2021-09-23 17:22:30 +02:00
/* const stub = document.createElement('div');
stub.classList.add(MEDIA_VIEWER_CLASSNAME + '-stub');
this.content.main.prepend(stub); */
this.content.caption = document.createElement('div');
this.content.caption.classList.add(MEDIA_VIEWER_CLASSNAME + '-caption'/* , 'media-viewer-stub' */);
let captionTimeout: number;
2021-08-19 13:37:17 +02:00
const setCaptionTimeout = () => {
if(captionTimeout) {
clearTimeout(captionTimeout);
}
captionTimeout = window.setTimeout(() => {
captionTimeout = undefined;
this.content.caption.classList.remove('is-focused');
}, 800);
};
this.content.caption.addEventListener('touchstart', () => {
if(!mediaSizes.isMobile) return;
2021-08-18 20:16:45 +02:00
this.content.caption.classList.add('is-focused');
if(captionTimeout) {
clearTimeout(captionTimeout);
captionTimeout = undefined;
}
2021-08-19 13:37:17 +02:00
document.addEventListener('touchend', setCaptionTimeout, {once: true});
});
2020-10-31 19:45:49 +01:00
2021-08-19 13:37:17 +02:00
const captionScrollable = new Scrollable(this.content.caption);
captionScrollable.onAdditionalScroll = setCaptionTimeout;
2020-10-31 19:45:49 +01:00
//this.content.main.append(this.content.caption);
this.wholeDiv.append(this.content.caption);
2021-08-20 16:49:32 +02:00
attachClickEvent(this.buttons.delete, this.onDeleteClick);
const buttons: ButtonMenuItemOptions[] = [{
icon: 'forward',
text: 'Forward',
onClick: this.onForwardClick
}, {
icon: 'download',
2021-04-04 17:39:17 +02:00
text: 'MediaViewer.Context.Download',
onClick: this.onDownloadClick
2021-08-20 16:49:32 +02:00
}, {
icon: 'delete danger',
text: 'Delete',
2021-08-20 16:49:32 +02:00
onClick: this.onDeleteClick
}];
this.setBtnMenuToggle(buttons);
this.btnMenuDelete = buttons[buttons.length - 1].element;
// * constructing html end
this.setListeners();
}
protected setListeners() {
super.setListeners();
this.buttons.forward.addEventListener('click', this.onForwardClick);
this.author.container.addEventListener('click', this.onAuthorClick);
const onCaptionClick = (e: MouseEvent) => {
if(e.target instanceof HTMLAnchorElement) { // close viewer if it's t.me/ redirect
const onclick = (e.target as HTMLElement).getAttribute('onclick');
if(!onclick || onclick.includes('showMaskedAlert')) {
return;
}
cancelEvent(e);
this.close().then(() => {
this.content.caption.removeEventListener('click', onCaptionClick, {capture: true});
(e.target as HTMLAnchorElement).click();
});
return false;
}
};
this.content.caption.addEventListener('click', onCaptionClick, {capture: true});
}
/* public close(e?: MouseEvent) {
const good = !this.setMoverAnimationPromise;
const promise = super.close(e);
if(good) { // clear
this.currentMessageId = 0;
this.peerId = 0;
}
return promise;
} */
2021-10-21 15:16:43 +02:00
protected getMessageByPeer(peerId: PeerId, mid: number) {
2021-10-05 22:40:07 +02:00
return this.searchContext.isScheduled ? appMessagesManager.getScheduledMessageByPeer(peerId, mid) : appMessagesManager.getMessageByPeer(peerId, mid);
}
onPrevClick = (target: AppMediaViewerTargetType) => {
2021-10-05 22:40:07 +02:00
this.openMedia(this.getMessageByPeer(target.peerId, target.mid), target.element, -1);
};
onNextClick = (target: AppMediaViewerTargetType) => {
2021-10-05 22:40:07 +02:00
this.openMedia(this.getMessageByPeer(target.peerId, target.mid), target.element, 1);
};
2021-08-20 16:49:32 +02:00
onDeleteClick = () => {
2021-09-23 17:22:30 +02:00
const target = this.target;
new PopupDeleteMessages(target.peerId, [target.mid], 'chat', () => {
this.target = {element: this.content.media} as any;
2021-08-20 16:49:32 +02:00
this.close();
});
};
onForwardClick = () => {
2021-09-23 17:22:30 +02:00
const target = this.target;
if(target.mid) {
//appSidebarRight.forwardTab.open([target.mid]);
new PopupForward({
2021-09-23 17:22:30 +02:00
[target.peerId]: [target.mid]
}, () => {
return this.close();
});
}
};
onAuthorClick = (e: MouseEvent) => {
2021-09-23 17:22:30 +02:00
const {mid, peerId} = this.target;
if(mid && mid !== Number.MAX_SAFE_INTEGER) {
2020-12-25 13:53:20 +01:00
const threadId = this.searchContext.threadId;
2021-10-21 15:16:43 +02:00
const message = this.getMessageByPeer(peerId, mid);
this.close(e)
//.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve())
.then(() => {
if(mediaSizes.isMobile) {
2021-03-28 20:37:11 +02:00
const tab = appSidebarRight.getTab(AppSharedMediaTab);
if(tab) {
tab.close();
}
}
2020-12-25 13:53:20 +01:00
appImManager.setInnerPeer(message.peerId, mid, threadId ? 'discussion' : undefined, threadId);
});
}
};
onDownloadClick = () => {
2021-09-23 17:22:30 +02:00
const {peerId, mid} = this.target;
2021-10-05 22:40:07 +02:00
const message = this.getMessageByPeer(peerId, mid);
if(message.media.photo) {
appPhotosManager.savePhotoFile(message.media.photo, appImManager.chat.bubbles.lazyLoadQueue.queueId);
} else {
let document: MyDocument = null;
if(message.media.webpage) document = message.media.webpage.document;
else document = message.media.document;
if(document) {
//console.log('will save document:', document);
appDocsManager.saveDocFile(document, appImManager.chat.bubbles.lazyLoadQueue.queueId);
}
}
};
2021-08-11 15:39:49 +02:00
private setCaption(message: Message.message) {
const caption = message.message;
2021-08-11 15:39:49 +02:00
let html = '';
if(caption) {
2021-08-11 15:39:49 +02:00
html = RichTextProcessor.wrapRichText(caption, {
entities: message.totalEntities
});
}
2021-08-11 15:39:49 +02:00
// html = 'Dandelion are a family of flowering plants that grow in many parts of the world.';
setInnerHTML(this.content.caption.firstElementChild, html);
this.content.caption.classList.toggle('hide', !caption);
// this.content.container.classList.toggle('with-caption', !!caption);
}
2021-10-05 22:40:07 +02:00
public setSearchContext(context: MediaSearchContext) {
this.listLoader.setSearchContext(context);
2020-12-25 13:53:20 +01:00
return this;
}
public async openMedia(message: any, target?: HTMLElement, fromRight = 0, reverse = false,
prevTargets: AppMediaViewerTargetType[] = [], nextTargets: AppMediaViewerTargetType[] = []/* , needLoadMore = true */) {
if(this.setMoverPromise) return this.setMoverPromise;
const mid = message.mid;
const fromId = message.fromId;
2021-08-18 16:48:13 +02:00
const media = appMessagesManager.getMediaFromMessage(message);
this.buttons.forward.classList.toggle('hide', message._ === 'messageService');
2021-08-20 16:49:32 +02:00
const canDeleteMessage = appMessagesManager.canDeleteMessage(message);
[this.buttons.delete, this.btnMenuDelete].forEach(button => {
button.classList.toggle('hide', !canDeleteMessage);
});
this.setCaption(message);
2021-10-05 22:40:07 +02:00
const promise = super._openMedia(media, message.date, fromId, fromRight, target, reverse, prevTargets, nextTargets, message/* , needLoadMore */);
this.target.mid = mid;
this.target.peerId = message.peerId;
return promise;
}
2021-08-18 16:48:13 +02:00
public static isMediaCompatibleForDocumentViewer(media: MyPhoto | MyDocument) {
return media._ === 'photo' || MEDIA_MIME_TYPES_SUPPORTED.has(media.mime_type);
2021-08-18 16:48:13 +02:00
}
}