Browse Source

Images .onload & several fixes

master
morethanwords 4 years ago
parent
commit
67aca5c877
  1. 28
      src/components/misc.ts
  2. 5
      src/components/scrollable.ts
  3. 36
      src/components/wrappers.ts
  4. 3
      src/lib/appManagers/appDialogsManager.ts
  5. 44
      src/lib/appManagers/appDocsManager.ts
  6. 191
      src/lib/appManagers/appImManager.ts
  7. 16
      src/lib/appManagers/appMediaViewer.ts
  8. 6
      src/lib/appManagers/appPhotosManager.ts
  9. 4
      src/lib/appManagers/appStickersManager.ts
  10. 14
      src/lib/appManagers/appWebpManager.ts
  11. 157
      src/lib/filemanager.ts
  12. 9
      src/scss/partials/_chat.scss

28
src/components/misc.ts

@ -92,14 +92,26 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool
}); });
} }
export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement, url: string) { let loadedURLs: {[url: string]: boolean} = {};
let img = new Image(); let set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string) => {
img.src = url; if(elem instanceof HTMLImageElement || elem instanceof HTMLSourceElement) elem.src = url;
img.onload = () => { else if(elem instanceof SVGImageElement) elem.setAttributeNS(null, 'href', url);
if(elem instanceof HTMLImageElement) elem.src = url; else elem.style.backgroundImage = 'url(' + url + ')';
else if(elem instanceof SVGImageElement) elem.setAttributeNS(null, 'href', url); };
else elem.style.backgroundImage = 'url(' + url + ')';
}; export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string) {
if(loadedURLs[url]) return set(elem, url);
if(elem instanceof HTMLSourceElement) {
return elem.src = url;
} else {
let loader = new Image();
loader.src = url;
loader.onload = () => {
set(elem, url);
loadedURLs[url] = true;
};
}
} }
export function putPreloader(elem: Element, returnDiv = false) { export function putPreloader(elem: Element, returnDiv = false) {

5
src/components/scrollable.ts

@ -875,9 +875,8 @@ export default class Scrollable {
public removeElement(element: Element) { public removeElement(element: Element) {
if(!this.splitUp) { if(!this.splitUp) {
if(this.container.contains(element)) { if(element.parentElement) {
//fastdom.mutate(() => this.container.removeChild(element)); element.remove();
this.container.removeChild(element);
} }
return; return;

36
src/components/wrappers.ts

@ -36,6 +36,7 @@ export type MTDocument = {
file?: File, file?: File,
duration?: number, duration?: number,
downloaded?: boolean, downloaded?: boolean,
url?: string,
version?: any, version?: any,
audioTitle?: string, audioTitle?: string,
@ -110,11 +111,10 @@ export function wrapVideo(this: AppImManager, doc: MTDocument, container: HTMLDi
//return; //return;
///////console.log('loaded doc:', doc, blob, container); console.log('loaded doc:', doc, doc.url, blob, container);
//source.src = doc.url; renderImageFromUrl(source, doc.url);
source.type = doc.mime_type; source.type = doc.mime_type;
source.src = URL.createObjectURL(blob);
video.append(source); video.append(source);
if(!withTail) { if(!withTail) {
@ -141,7 +141,7 @@ export function wrapVideo(this: AppImManager, doc: MTDocument, container: HTMLDi
}; };
if(doc.type == 'gif' || true) { // extra fix if(doc.type == 'gif' || true) { // extra fix
return this.lazyLoadQueue.push({div: container, load: loadVideo, wasSeen: true}); return doc.downloaded ? loadVideo() : this.lazyLoadQueue.push({div: container, load: loadVideo, wasSeen: true});
} /* else { // if video } /* else { // if video
let load = () => appPhotosManager.preloadPhoto(doc).then((blob) => { let load = () => appPhotosManager.preloadPhoto(doc).then((blob) => {
if((this.peerID ? this.peerID : this.currentMessageID) != peerID) { if((this.peerID ? this.peerID : this.currentMessageID) != peerID) {
@ -446,7 +446,7 @@ function wrapMediaWithTail(photo: any, message: {mid: number, message: string},
let image = document.createElementNS("http://www.w3.org/2000/svg", "image"); let image = document.createElementNS("http://www.w3.org/2000/svg", "image");
svg.append(image); svg.append(image);
let size = appPhotosManager.setAttachmentSize(photo.type ? photo : photo.id, svg, boxWidth, boxHeight, false); let size = appPhotosManager.setAttachmentSize(photo._ == 'document' ? photo : photo.id, svg, boxWidth, boxHeight);
let width = +svg.getAttributeNS(null, 'width'); let width = +svg.getAttributeNS(null, 'width');
let height = +svg.getAttributeNS(null, 'height'); let height = +svg.getAttributeNS(null, 'height');
@ -540,7 +540,7 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
console.log('wrap sticker', doc, div, onlyThumb); console.log('wrap sticker', doc, div, onlyThumb);
if(doc.thumbs && !div.firstElementChild) { if(doc.thumbs && !div.firstElementChild && (!doc.downloaded || stickerType == 2)) {
let thumb = doc.thumbs[0]; let thumb = doc.thumbs[0];
console.log('wrap sticker', thumb, div); console.log('wrap sticker', thumb, div);
@ -652,17 +652,19 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
reader.readAsArrayBuffer(blob); reader.readAsArrayBuffer(blob);
} else if(stickerType == 1) { } else if(stickerType == 1) {
let img = new Image(); let img = new Image();
appWebpManager.polyfillImage(img, blob).then(() => { if(!doc.url) {
if(div.firstElementChild && div.firstElementChild != img) { appWebpManager.polyfillImage(img, blob).then((url) => {
div.firstElementChild.remove(); doc.url = url;
}
}); if(div.firstElementChild && div.firstElementChild != img) {
div.firstElementChild.remove();
//img.src = URL.createObjectURL(blob); }
});
/* div.style.height = doc.h + 'px'; } else {
div.style.width = doc.w + 'px'; */ img.src = doc.url;
}
div.append(img); div.append(img);
} }

3
src/lib/appManagers/appDialogsManager.ts

@ -218,8 +218,7 @@ export class AppDialogsManager {
} }
let img = new Image(); let img = new Image();
img.src = this.savedAvatarURLs[peerID]; renderImageFromUrl(img, this.savedAvatarURLs[peerID]);
//renderImageFromUrl(img, this.savedAvatarURLs[peerID]);
div.innerHTML = ''; div.innerHTML = '';
//div.style.fontSize = '0'; // need //div.style.fontSize = '0'; // need
//div.style.backgroundColor = ''; //div.style.backgroundColor = '';

44
src/lib/appManagers/appDocsManager.ts

@ -37,10 +37,10 @@ class AppDocsManager {
break; break;
case 'documentAttributeAudio': case 'documentAttributeAudio':
apiDoc.duration = attribute.duration apiDoc.duration = attribute.duration;
apiDoc.audioTitle = attribute.title apiDoc.audioTitle = attribute.title;
apiDoc.audioPerformer = attribute.performer apiDoc.audioPerformer = attribute.performer;
apiDoc.type = attribute.pFlags.voice ? 'voice' : 'audio' apiDoc.type = attribute.pFlags.voice ? 'voice' : 'audio';
break; break;
case 'documentAttributeVideo': case 'documentAttributeVideo':
@ -49,7 +49,7 @@ class AppDocsManager {
apiDoc.h = attribute.h; apiDoc.h = attribute.h;
if(apiDoc.thumbs && attribute.pFlags.round_message) { if(apiDoc.thumbs && attribute.pFlags.round_message) {
apiDoc.type = 'round'; apiDoc.type = 'round';
} else if(apiDoc.thumbs) { } else /* if(apiDoc.thumbs) */ {
apiDoc.type = 'video'; apiDoc.type = 'video';
} }
break; break;
@ -64,14 +64,14 @@ class AppDocsManager {
if(attribute.stickerset) { if(attribute.stickerset) {
if(attribute.stickerset._ == 'inputStickerSetEmpty') { if(attribute.stickerset._ == 'inputStickerSetEmpty') {
delete attribute.stickerset delete attribute.stickerset;
} else if(attribute.stickerset._ == 'inputStickerSetID') { } else if(attribute.stickerset._ == 'inputStickerSetID') {
apiDoc.stickerSetInput = attribute.stickerset apiDoc.stickerSetInput = attribute.stickerset;
} }
} }
if(apiDoc.thumbs && apiDoc.mime_type == 'image/webp') { if(apiDoc.thumbs && apiDoc.mime_type == 'image/webp') {
apiDoc.type = 'sticker' apiDoc.type = 'sticker';
} else if(apiDoc.mime_type == 'application/x-tgsticker') { } else if(apiDoc.mime_type == 'application/x-tgsticker') {
apiDoc.type = 'sticker'; apiDoc.type = 'sticker';
apiDoc.animated = true; apiDoc.animated = true;
@ -103,22 +103,22 @@ class AppDocsManager {
apiDoc.mime_type = 'video/mp4'; apiDoc.mime_type = 'video/mp4';
break; break;
case 'sticker': case 'sticker':
apiDoc.mime_type = 'image/webp' apiDoc.mime_type = 'image/webp';
break break;
case 'audio': case 'audio':
apiDoc.mime_type = 'audio/mpeg' apiDoc.mime_type = 'audio/mpeg';
break break;
case 'voice': case 'voice':
apiDoc.mime_type = 'audio/ogg' apiDoc.mime_type = 'audio/ogg';
break break;
default: default:
apiDoc.mime_type = 'application/octet-stream' apiDoc.mime_type = 'application/octet-stream';
break break;
} }
} }
if(!apiDoc.file_name) { if(!apiDoc.file_name) {
apiDoc.file_name = '' apiDoc.file_name = '';
} }
if(apiDoc._ == 'documentEmpty') { if(apiDoc._ == 'documentEmpty') {
@ -132,10 +132,6 @@ class AppDocsManager {
return this.docs[docID] || {_: 'documentEmpty'}; return this.docs[docID] || {_: 'documentEmpty'};
} }
public hasDoc(docID: string) {
return this.docs[docID] !== undefined;
}
public getFileName(doc: MTDocument) { public getFileName(doc: MTDocument) {
if(doc.file_name) { if(doc.file_name) {
return doc.file_name; return doc.file_name;
@ -209,9 +205,9 @@ class AppDocsManager {
if(blob) { if(blob) {
doc.downloaded = true; doc.downloaded = true;
/* FileManager.getFileCorrectUrl(blob, doc.mime_type).then((url) => { if(/* !doc.animated || */doc.type != 'sticker') {
doc.url = url; doc.url = FileManager.getFileCorrectUrl(blob, doc.mime_type);
}); */ }
} }
/* doc.progress.percent = 100; /* doc.progress.percent = 100;

191
src/lib/appManagers/appImManager.ts

@ -28,76 +28,6 @@ console.log('appImManager included!');
let testScroll = false; let testScroll = false;
class ScrollPosition {
previousScrollHeightMinusTop = 0;
readyFor = 'up';
container: HTMLElement;
rAF: number;
debug = true;
prepared = false;
constructor(node: HTMLElement) {
this.container = node.parentElement;
}
restore(callback?: () => void) {
return;
let setScrollTop = this.container.scrollHeight - this.previousScrollHeightMinusTop;
if(this.debug) appImManager.log('scrollPosition restore', this.readyFor, this.container.scrollHeight,
setScrollTop, this.container, this.container.parentElement.classList.contains('scrolled-down'));
if(this.readyFor === 'up' || this.container.parentElement.classList.contains('scrolled-down')) {
if(this.debug) appImManager.log('scrollPosition restore 2', this.readyFor, this.container.scrollHeight,
setScrollTop, this.container);
if(this.rAF) window.cancelAnimationFrame(this.rAF);
this.rAF = window.requestAnimationFrame(() => {
this.container.scrollTop = this.container.scrollHeight - this.previousScrollHeightMinusTop;
this.rAF = 0;
this.prepared = false;
callback && callback();
});
}/* else if(this.container.parentElement.classList.contains('scrolled-down')) {
if(this.debug) appImManager.log('scrollPosition restore 2', this.readyFor, this.container.scrollHeight,
setScrollTop, this.container);
this.container.scrollTop = setScrollTop;
this.prepared = false;
} */
// 'down' doesn't need to be special cased unless the
// content was flowing upwards, which would only happen
// if the container is position: absolute, bottom: 0 for
// a Facebook messages effect
}
prepareFor(direction = 'up') {
return;
//if(this.prepared) return;
if(this.rAF) {
window.cancelAnimationFrame(this.rAF);
this.rAF = 0;
}
this.readyFor = direction;
if(direction == 'down') {
let scrollTop = this.container.scrollTop;
this.previousScrollHeightMinusTop = scrollTop > 0 ? this.container.scrollHeight - scrollTop : 0;
} else {
this.previousScrollHeightMinusTop = this.container.scrollHeight - this.container.scrollTop;
}
//let scrollTop = this.container.scrollTop;
//this.previousScrollHeightMinusTop = scrollTop > 0 || this.readyFor == 'up' ? this.container.scrollHeight - this.container.scrollTop : 0;
if(this.debug) appImManager.log.warn('scrollPosition prepareFor', direction, this.container.scrollHeight,
this.container.scrollTop, this.previousScrollHeightMinusTop);
}
}
export class AppImManager { export class AppImManager {
public pageEl = document.querySelector('.page-chats') as HTMLDivElement; public pageEl = document.querySelector('.page-chats') as HTMLDivElement;
public btnMute = this.pageEl.querySelector('.tool-mute') as HTMLButtonElement; public btnMute = this.pageEl.querySelector('.tool-mute') as HTMLButtonElement;
@ -142,8 +72,7 @@ export class AppImManager {
public scroll: HTMLDivElement = null; public scroll: HTMLDivElement = null;
public scrollable: Scrollable = null; public scrollable: Scrollable = null;
public scrollPosition: ScrollPosition = null;
public log: ReturnType<typeof logger>; public log: ReturnType<typeof logger>;
private preloader: ProgressivePreloader = null; private preloader: ProgressivePreloader = null;
@ -171,6 +100,8 @@ export class AppImManager {
private setPeerPromise: Promise<boolean> = null; private setPeerPromise: Promise<boolean> = null;
public bubbleGroups = new BubbleGroups(); public bubbleGroups = new BubbleGroups();
private scrolledDown = true;
constructor() { constructor() {
/* if(!lottieLoader.loaded) { /* if(!lottieLoader.loaded) {
@ -204,7 +135,7 @@ export class AppImManager {
$rootScope.$on('history_append', (e: CustomEvent) => { $rootScope.$on('history_append', (e: CustomEvent) => {
let details = e.detail; let details = e.detail;
this.renderMessagesByIDs([details.messageID]); this.renderNewMessagesByIDs([details.messageID]);
}); });
// will call when sent for update pos // will call when sent for update pos
@ -221,8 +152,6 @@ export class AppImManager {
//this.log('history_update', this.bubbles[mid], mid, message); //this.log('history_update', this.bubbles[mid], mid, message);
this.renderMessage(message, false, false, bubble); this.renderMessage(message, false, false, bubble);
this.deleteEmptySideDivs();
} }
}); });
@ -232,9 +161,7 @@ export class AppImManager {
let msgIDs = msgIDsByPeer[this.peerID]; let msgIDs = msgIDsByPeer[this.peerID];
this.renderMessagesByIDs(msgIDs); this.renderNewMessagesByIDs(msgIDs);
//appDialogsManager.sortDom();
}); });
$rootScope.$on('history_delete', (e: CustomEvent) => { $rootScope.$on('history_delete', (e: CustomEvent) => {
@ -244,10 +171,6 @@ export class AppImManager {
} = e.detail; } = e.detail;
this.deleteMessagesByIDs(Object.keys(detail.msgs).map(s => +s)); this.deleteMessagesByIDs(Object.keys(detail.msgs).map(s => +s));
setTimeout(() => {
this.deleteEmptySideDivs();
}, 0);
}); });
// Calls when message successfully sent and we have an ID // Calls when message successfully sent and we have an ID
@ -667,37 +590,6 @@ export class AppImManager {
}); });
} }
public deleteEmptySideDivs() {
return;
let nodes = Array.from(this.chatInner.childNodes) as HTMLDivElement[];
nodes.filter((node) => {
let childElementCount = node.childElementCount;
if(!childElementCount) {
node.remove();
return false;
} else if(childElementCount == 1) {
let child = node.firstElementChild;
if(child.classList.contains('service')) {
node.remove();
return false;
}
}
return true;
}).forEach(node => {
let nextNode = node.nextElementSibling;
if(nextNode && node.className == nextNode.className) {
(Array.from(node.childNodes) as HTMLDivElement[]).reverse().forEach(div => {
nextNode.prepend(div);
});
node.remove();
}
});
}
public updateStatus() { public updateStatus() {
if(!this.myID) return Promise.resolve(); if(!this.myID) return Promise.resolve();
@ -779,8 +671,10 @@ export class AppImManager {
if(this.scroll.scrollHeight - (this.scroll.scrollTop + this.scroll.offsetHeight) == 0/* <= 5 */) { if(this.scroll.scrollHeight - (this.scroll.scrollTop + this.scroll.offsetHeight) == 0/* <= 5 */) {
this.scroll.parentElement.classList.add('scrolled-down'); this.scroll.parentElement.classList.add('scrolled-down');
this.scrolledDown = true;
} else if(this.scroll.parentElement.classList.contains('scrolled-down')) { } else if(this.scroll.parentElement.classList.contains('scrolled-down')) {
this.scroll.parentElement.classList.remove('scrolled-down'); this.scroll.parentElement.classList.remove('scrolled-down');
this.scrolledDown = false;
} }
} }
@ -793,8 +687,7 @@ export class AppImManager {
//this.scrollable.setVirtualContainer(this.chatInner); //this.scrollable.setVirtualContainer(this.chatInner);
this.scrollable.onScrolledTop = () => this.loadMoreHistory(true); this.scrollable.onScrolledTop = () => this.loadMoreHistory(true);
this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false); this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);
this.scrollPosition = new ScrollPosition(this.chatInner);
this.scroll.addEventListener('scroll', this.onScroll.bind(this)); this.scroll.addEventListener('scroll', this.onScroll.bind(this));
this.scroll.parentElement.classList.add('scrolled-down'); this.scroll.parentElement.classList.add('scrolled-down');
} }
@ -931,6 +824,7 @@ export class AppImManager {
this.getHistoryTopPromise = this.getHistoryBottomPromise = undefined; this.getHistoryTopPromise = this.getHistoryBottomPromise = undefined;
//this.scrollable.setVirtualContainer(this.chatInner); //this.scrollable.setVirtualContainer(this.chatInner);
this.scrollable.setVirtualContainer(null);
////console.timeEnd('appImManager cleanup'); ////console.timeEnd('appImManager cleanup');
} }
@ -996,6 +890,8 @@ export class AppImManager {
this.chatInner.style.visibility = 'hidden'; this.chatInner.style.visibility = 'hidden';
this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : ''; this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : '';
this.topbar.style.display = ''; this.topbar.style.display = '';
if(appPeersManager.isAnyGroup(peerID)) this.chatInner.classList.add('is-chat');
else this.chatInner.classList.remove('is-chat');
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
//this.chatInner.style.visibility = 'hidden'; //this.chatInner.style.visibility = 'hidden';
@ -1010,8 +906,8 @@ export class AppImManager {
//this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : ''; //this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : '';
//appSidebarRight.toggleSidebar(true); //appSidebarRight.toggleSidebar(true);
if(appPeersManager.isAnyGroup(peerID)) this.chatInner.classList.add('is-chat'); //if(appPeersManager.isAnyGroup(peerID)) this.chatInner.classList.add('is-chat');
else this.chatInner.classList.remove('is-chat'); //else this.chatInner.classList.remove('is-chat');
if(!fromClick) { if(!fromClick) {
if(!samePeer && appDialogsManager.lastActiveListElement) { if(!samePeer && appDialogsManager.lastActiveListElement) {
@ -1141,12 +1037,13 @@ export class AppImManager {
lottieLoader.checkAnimations(); lottieLoader.checkAnimations();
} }
public renderMessagesByIDs(msgIDs: number[]) { public renderNewMessagesByIDs(msgIDs: number[]) {
if(!this.bubbles[this.firstTopMsgID] && Object.keys(this.bubbles).length) { // seems search active if(!this.bubbles[this.firstTopMsgID] && Object.keys(this.bubbles).length) { // seems search active
//////this.log('seems search is active, skipping render:', msgIDs); //////this.log('seems search is active, skipping render:', msgIDs);
return; return;
} }
let scrolledDown = this.scrolledDown;
msgIDs.forEach((msgID: number) => { msgIDs.forEach((msgID: number) => {
let message = appMessagesManager.getMessage(msgID); let message = appMessagesManager.getMessage(msgID);
@ -1155,10 +1052,11 @@ export class AppImManager {
//this.unreaded.push(msgID); //this.unreaded.push(msgID);
this.renderMessage(message); this.renderMessage(message);
}); });
if(scrolledDown) this.scrollable.scrollTop = this.scrollable.scrollHeight;
} }
// reverse means top, will save scrollPosition if bubble will be higher // reverse means top
public renderMessage(message: any, reverse = false, multipleRender?: boolean, bubble: HTMLDivElement = null, updatePosition = true) { public renderMessage(message: any, reverse = false, multipleRender = false, bubble: HTMLDivElement = null, updatePosition = true) {
/////this.log('message to render:', message); /////this.log('message to render:', message);
if(message.deleted) return; if(message.deleted) return;
@ -1169,11 +1067,7 @@ export class AppImManager {
messageDiv.classList.add('message'); messageDiv.classList.add('message');
//messageDiv.innerText = message.message; //messageDiv.innerText = message.message;
if(!multipleRender) {
this.scrollPosition.prepareFor(reverse ? 'up' : 'down'); // лагает из-за этого
}
let bubbleContainer: HTMLDivElement; let bubbleContainer: HTMLDivElement;
// bubble // bubble
@ -1406,8 +1300,7 @@ export class AppImManager {
if(webpage.photo && !doc) { if(webpage.photo && !doc) {
bubble.classList.add('photo'); bubble.classList.add('photo');
//appPhotosManager.savePhoto(webpage.photo); // hot-fix because no webpage manager
wrapPhoto.call(this, webpage.photo.id, message, preview, 380, 300, false); wrapPhoto.call(this, webpage.photo.id, message, preview, 380, 300, false);
} }
@ -1440,10 +1333,7 @@ export class AppImManager {
case 'messageMediaDocument': { case 'messageMediaDocument': {
let doc = message.media.document; let doc = message.media.document;
/* if(document.size > 1e6) { // 1mb
break;
} */
this.log('messageMediaDocument', doc, bubble); this.log('messageMediaDocument', doc, bubble);
if(doc.sticker && doc.size <= 1e6) { if(doc.sticker && doc.size <= 1e6) {
@ -1468,7 +1358,7 @@ export class AppImManager {
}, this.lazyLoadQueue, 'chat', false, !!message.pending || !multipleRender); }, this.lazyLoadQueue, 'chat', false, !!message.pending || !multipleRender);
break; break;
} else if(doc.mime_type == 'video/mp4' && doc.size <= 20e6) { } else if((doc.type == 'video' || doc.type == 'gif') && doc.size <= 20e6) {
this.log('never get free 2', doc); this.log('never get free 2', doc);
if(doc.type == 'round') { if(doc.type == 'round') {
@ -1614,16 +1504,13 @@ export class AppImManager {
} else { } else {
this.scrollable.appendByBatch(bubble); this.scrollable.appendByBatch(bubble);
} */ } */
/* if(reverse) { if(!multipleRender) {
this.scrollable.prepend(bubble); if(reverse) {
this.scrollable.prepend(bubble);
if(!this.scrollable.scrollTop) { } else {
let height = bubble.scrollHeight; this.scrollable.append(bubble);
this.scrollable.scrollTop += height;
} }
} else { }
this.scrollable.append(bubble);
} */
//}); //});
let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
@ -1681,12 +1568,6 @@ export class AppImManager {
/* if(bubble.classList.contains('webpage')) { /* if(bubble.classList.contains('webpage')) {
this.log('night running', bubble, bubble.scrollHeight); this.log('night running', bubble, bubble.scrollHeight);
} */ } */
//return //this.scrollPosition.restore();
if(!multipleRender) {
this.scrollPosition.restore(); // лагает из-за этого
}
return bubble; return bubble;
} }
@ -1714,10 +1595,6 @@ export class AppImManager {
//console.time('appImManager render history'); //console.time('appImManager render history');
this.log('getHistory method', method); this.log('getHistory method', method);
if(!isBackLimit) {
this.scrollPosition.prepareFor(reverse ? 'up' : 'down');
}
let firstLoad = !!this.setPeerPromise && false; let firstLoad = !!this.setPeerPromise && false;
@ -1731,7 +1608,7 @@ export class AppImManager {
bubbles.push(bubble); bubbles.push(bubble);
}); */ }); */
//let innerHeight = this.scrollable.innerHeight; let leftHeightToScroll = this.scrollable.innerHeight;
//console.timeEnd('appImManager: pre render start'); //console.timeEnd('appImManager: pre render start');
@ -1789,7 +1666,12 @@ export class AppImManager {
//let height = Math.ceil(bubble.getBoundingClientRect().height); //let height = Math.ceil(bubble.getBoundingClientRect().height);
this.scrollable.scrollTop += height; this.scrollable.scrollTop += height;
//innerHeight -= height; //innerHeight -= height;
} else { }
/* if(leftHeightToScroll >= 0) {
let height = bubble.scrollHeight;
leftHeightToScroll -= height;
this.scrollable.scrollTop += height;
} */ else {
renderedFirstScreen = true; renderedFirstScreen = true;
resolve(); resolve();
resolved = true; resolved = true;
@ -1906,7 +1788,8 @@ export class AppImManager {
return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise); return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
} else { } else {
let promise = this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true); let promise = this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);
return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise); //return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
return promise;
//return this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true); //return this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);
} }
} }

16
src/lib/appManagers/appMediaViewer.ts

@ -8,6 +8,7 @@ import ProgressivePreloader from "../../components/preloader";
import { findUpClassName, $rootScope, generatePathData } from "../utils"; import { findUpClassName, $rootScope, generatePathData } from "../utils";
import appDocsManager from "./appDocsManager"; import appDocsManager from "./appDocsManager";
import { wrapPlayer } from "../ckin"; import { wrapPlayer } from "../ckin";
import { renderImageFromUrl } from "../../components/misc";
export class AppMediaViewer { export class AppMediaViewer {
private overlaysDiv = document.querySelector('.overlays') as HTMLDivElement; private overlaysDiv = document.querySelector('.overlays') as HTMLDivElement;
@ -514,9 +515,8 @@ export class AppMediaViewer {
public updateMediaSource(target: HTMLElement, url: string, tagName: 'source' | 'image') { public updateMediaSource(target: HTMLElement, url: string, tagName: 'source' | 'image') {
//if(target instanceof SVGSVGElement) { //if(target instanceof SVGSVGElement) {
let el = target.querySelector(tagName); let el = target.querySelector(tagName) as HTMLElement;
if(tagName == 'source') (el as HTMLSourceElement).src = url; renderImageFromUrl(el, url);
else el.setAttributeNS(null, 'href', url);
/* } else { /* } else {
} */ } */
@ -644,7 +644,7 @@ export class AppMediaViewer {
return; return;
} }
let url = URL.createObjectURL(blob); let url = media.url;
if(target instanceof SVGSVGElement) { if(target instanceof SVGSVGElement) {
this.updateMediaSource(mover, url, 'source'); this.updateMediaSource(mover, url, 'source');
this.updateMediaSource(target, url, 'source'); this.updateMediaSource(target, url, 'source');
@ -655,8 +655,7 @@ export class AppMediaViewer {
} }
source = document.createElement('source'); source = document.createElement('source');
//source.src = doc.url; renderImageFromUrl(source, url);
source.src = url;
source.type = media.mime_type; source.type = media.mime_type;
mover.prepend(video); mover.prepend(video);
@ -703,13 +702,14 @@ export class AppMediaViewer {
///////this.log('indochina', blob); ///////this.log('indochina', blob);
let url = URL.createObjectURL(blob); let url = media.url;
if(target instanceof SVGSVGElement) { if(target instanceof SVGSVGElement) {
this.updateMediaSource(target, url, 'image'); this.updateMediaSource(target, url, 'image');
this.updateMediaSource(mover, url, 'image'); this.updateMediaSource(mover, url, 'image');
} else { } else {
let image = mover.firstElementChild as HTMLImageElement || new Image(); let image = mover.firstElementChild as HTMLImageElement || new Image();
image.src = url; //image.src = url;
renderImageFromUrl(image, url);
mover.prepend(image); mover.prepend(image);
} }

6
src/lib/appManagers/appPhotosManager.ts

@ -2,7 +2,7 @@ import appUsersManager from "./appUsersManager";
import { copy, calcImageInBox } from "../utils"; import { copy, calcImageInBox } from "../utils";
import fileManager from '../filemanager'; import fileManager from '../filemanager';
import { bytesFromHex } from "../bin_utils"; import { bytesFromHex } from "../bin_utils";
import { MTPhotoSize } from "../../components/wrappers"; import { MTPhotoSize, MTDocument } from "../../components/wrappers";
import apiFileManager from "../mtproto/apiFileManager"; import apiFileManager from "../mtproto/apiFileManager";
import apiManager from "../mtproto/apiManager"; import apiManager from "../mtproto/apiManager";
@ -207,7 +207,7 @@ export class AppPhotosManager {
//console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div); //console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);
let sizes = photo.sizes || photo.thumbs; let sizes = photo.sizes || photo.thumbs;
if((!photo.downloaded || isSticker) && sizes && sizes[0].bytes) { if((!photo.downloaded || (isSticker && photo.animated)) && sizes && sizes[0].bytes) {
this.setAttachmentPreview(sizes[0].bytes, element, isSticker); this.setAttachmentPreview(sizes[0].bytes, element, isSticker);
} }
@ -225,6 +225,8 @@ export class AppPhotosManager {
if(element instanceof SVGSVGElement) { if(element instanceof SVGSVGElement) {
element.setAttributeNS(null, 'width', '' + w); element.setAttributeNS(null, 'width', '' + w);
element.setAttributeNS(null, 'height', '' + h); element.setAttributeNS(null, 'height', '' + h);
console.log('set dimensions to svg element:', element, w, h);
if(element.firstElementChild) { if(element.firstElementChild) {
let imageSvg = element.firstElementChild as SVGImageElement; let imageSvg = element.firstElementChild as SVGImageElement;

4
src/lib/appManagers/appStickersManager.ts

@ -129,7 +129,7 @@ class appStickersManager {
}); */ }); */
} }
public async getStickerSetThumb(stickerSet: MTStickerSet) { public getStickerSetThumb(stickerSet: MTStickerSet) {
let thumb = stickerSet.thumb; let thumb = stickerSet.thumb;
let dcID = stickerSet.thumb_dc_id; let dcID = stickerSet.thumb_dc_id;
@ -144,7 +144,7 @@ class appStickersManager {
local_id: thumb.location.local_id local_id: thumb.location.local_id
}, {dcID: dcID}); }, {dcID: dcID});
return await promise; return promise;
} }
public async cleanup() { // if logout public async cleanup() { // if logout

14
src/lib/appManagers/appWebpManager.ts

@ -5,7 +5,7 @@ class AppWebpManager {
public webpMachine: any = null; public webpMachine: any = null;
public loaded: Promise<void>; public loaded: Promise<void>;
public busyPromise: Promise<string>; public busyPromise: Promise<string>;
public queue: {bytes: Uint8Array, img: HTMLImageElement, callback: () => void}[] = []; public queue: {bytes: Uint8Array, img: HTMLImageElement, callback: (url: string) => void}[] = [];
//public worker: any; //public worker: any;
public webpSupport: Promise<boolean> = null; public webpSupport: Promise<boolean> = null;
@ -65,12 +65,13 @@ class AppWebpManager {
await this.loaded; await this.loaded;
this.busyPromise = this.convert(bytes); this.busyPromise = this.convert(bytes);
let url = await this.busyPromise;
let imgTemp = new Image(); let imgTemp = new Image();
imgTemp.src = await this.busyPromise; imgTemp.src = url;
imgTemp.onload = () => { imgTemp.onload = () => {
img.src = imgTemp.src; img.src = imgTemp.src;
}; };
callback(); callback(url);
this.busyPromise = null; this.busyPromise = null;
@ -98,11 +99,12 @@ class AppWebpManager {
//if(await this.webpMachine.webpSupport) { //if(await this.webpMachine.webpSupport) {
if(await this.webpSupport) { if(await this.webpSupport) {
img.src = URL.createObjectURL(blob); let url = URL.createObjectURL(blob);
return; img.src = url;
return url;
} }
return new Promise((resolve, reject) => { return new Promise<string>((resolve, reject) => {
const reader = new FileReader(); const reader = new FileReader();
reader.addEventListener('loadend', (e) => { reader.addEventListener('loadend', (e) => {
// @ts-ignore // @ts-ignore

157
src/lib/filemanager.ts

@ -8,11 +8,6 @@ if(window.location.href.indexOf('localhost') === -1) {
} }
class FileManager { class FileManager {
public isSafari = 'safari' in window;
public safariVersion = parseFloat(this.isSafari && (navigator.userAgent.match(/Version\/(\d+\.\d+).* Safari/) || [])[1]);
public safariWithDownload = this.isSafari && this.safariVersion >= 11.0;
public buggyUnknownBlob = this.isSafari && !this.safariWithDownload;
public blobSupported = true; public blobSupported = true;
constructor() { constructor() {
@ -93,12 +88,12 @@ class FileManager {
let fileReader = new FileReader(); let fileReader = new FileReader();
fileReader.onload = function(event) { fileReader.onload = function(event) {
let arrayBuffer = event.target.result as ArrayBuffer; let arrayBuffer = event.target.result as ArrayBuffer;
let arr = new Uint8Array(arrayBuffer); let arr = new Uint8Array(arrayBuffer);
fileWriter.write(arr).then(resolve, reject); fileWriter.write(arr).then(resolve, reject);
}; };
fileReader.readAsArrayBuffer(bytes); fileReader.readAsArrayBuffer(bytes);
}); });
} else { } else {
@ -117,7 +112,7 @@ class FileManager {
let writer = fileStream.getWriter(); let writer = fileStream.getWriter();
return writer; return writer;
} }
public getFakeFileWriter(mimeType: string, saveFileCallback: any) { public getFakeFileWriter(mimeType: string, saveFileCallback: any) {
var blobParts: Array<Blob> = []; var blobParts: Array<Blob> = [];
var fakeFileWriter = { var fakeFileWriter = {
@ -143,76 +138,16 @@ class FileManager {
return fakeFileWriter; return fakeFileWriter;
} }
public getUrl(fileData: any, mimeType: string) { public getFileCorrectUrl(fileData: Blob | number[], mimeType: string): string {
var safeMimeType = blobSafeMimeType(mimeType); var safeMimeType = blobSafeMimeType(mimeType);
// console.log(dT(), 'get url', fileData, mimeType, fileData.toURL !== undefined, fileData instanceof Blob)
if(fileData.toURL !== undefined) {
return fileData.toURL(safeMimeType);
}
if(fileData instanceof Blob) { if(fileData instanceof Blob) {
return URL.createObjectURL(fileData); return URL.createObjectURL(fileData);
} }
return 'data:' + safeMimeType + ';base64,' + bytesToBase64(fileData); return 'data:' + safeMimeType + ';base64,' + bytesToBase64(fileData);
} }
public getByteArray(fileData: any) { public download(blob: Blob, mimeType: string, fileName: string) {
if(fileData instanceof Blob) {
return new Promise((resolve, reject) => {
try {
var reader = new FileReader();
reader.onloadend = (e) => {
// @ts-ignore
resolve(new Uint8Array(e.target.result));
};
reader.onerror = (e) => {
reject(e);
};
reader.readAsArrayBuffer(fileData);
} catch(e) {
reject(e);
}
});
} else if(fileData.file) {
return new Promise((resolve, reject) => {
fileData.file((blob: any) => {
this.getByteArray(blob).then(resolve, reject);
}, reject);
});
}
return Promise.resolve(fileData);
//return $q.when(fileData);
}
public getDataUrl(blob: any) {
return new Promise((resolve, reject) => {
try {
var reader = new FileReader();
reader.onloadend = () => {
resolve(reader.result);
};
reader.readAsDataURL(blob);
} catch (e) {
reject(e);
}
});
}
public getFileCorrectUrl(blob: any, mimeType: string) {
if(this.buggyUnknownBlob && blob instanceof Blob) {
// @ts-ignore
mimeType = blob.type || blob.mimeType || mimeType || ''
if(!mimeType.match(/image\/(jpeg|gif|png|bmp)|video\/quicktime/)) {
return this.getDataUrl(blob);
}
}
return Promise.resolve(this.getUrl(blob, mimeType));
}
// downloadFile
public download(blob: any, mimeType: string, fileName: string) {
if(window.navigator && navigator.msSaveBlob !== undefined) { if(window.navigator && navigator.msSaveBlob !== undefined) {
window.navigator.msSaveBlob(blob, fileName); window.navigator.msSaveBlob(blob, fileName);
return false; return false;
@ -244,57 +179,37 @@ class FileManager {
return; return;
} }
var popup: Window; let url = this.getFileCorrectUrl(blob, mimeType);
if(this.isSafari && !this.safariWithDownload) { var anchor = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') as HTMLAnchorElement;
popup = window.open(); anchor.href = url as string;
anchor.download = fileName;
if(anchor.dataset) {
anchor.dataset.downloadurl = ['video/quicktime', fileName, url].join(':');
} }
this.getFileCorrectUrl(blob, mimeType).then((url) => { anchor.style.position = 'absolute';
if(popup) { anchor.style.top = '1px';
try { anchor.style.left = '1px';
// @ts-ignore
popup.location.href = url; document.body.append(anchor);
return;
} catch (e) {} try {
} var clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
var anchor = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') as HTMLAnchorElement; anchor.dispatchEvent(clickEvent);
anchor.href = url as string; } catch (e) {
if(!this.safariWithDownload) { console.error('Download click error', e);
anchor.target = '_blank';
}
anchor.download = fileName;
if(anchor.dataset) {
anchor.dataset.downloadurl = ['video/quicktime', fileName, url].join(':');
}
anchor.style.position = 'absolute';
anchor.style.top = '1px';
anchor.style.left = '1px';
document.body.append(anchor);
try { try {
var clickEvent = document.createEvent('MouseEvents'); anchor.click();
clickEvent.initMouseEvent( } catch (e) {
'click', true, false, window, 0, 0, 0, 0, 0 window.open(url as string, '_blank');
, false, false, false, false, 0, null }
)
anchor.dispatchEvent(clickEvent);
} catch (e) {
console.error('Download click error', e);
try {
anchor.click();
} catch (e) {
window.open(url as string, '_blank');
}
}
setTimeout(() => {
anchor.remove();
}, 100);
})
} }
setTimeout(() => {
anchor.remove();
}, 100);
} }
}
export default new FileManager();
export default new FileManager();

9
src/scss/partials/_chat.scss

@ -121,7 +121,10 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
display: flex; // for end //display: flex; // for end
//flex-direction: unset;
display: block;
/* display: flex; /* display: flex;
flex-direction: column; flex-direction: column;
@ -156,9 +159,9 @@
//padding-top: 9px; //padding-top: 9px;
margin: 0 auto; margin: 0 auto;
box-sizing: border-box; box-sizing: border-box;
/* min-height: 100%; */ min-height: 100%;
justify-content: flex-end; justify-content: flex-end;
flex: 1; //flex: 1;
&.is-chat { &.is-chat {
.is-in .bubble__container { .is-in .bubble__container {

Loading…
Cancel
Save