diff --git a/src/components/scrollable.ts b/src/components/scrollable.ts index 208d4044..cfb0a993 100644 --- a/src/components/scrollable.ts +++ b/src/components/scrollable.ts @@ -86,7 +86,7 @@ export default class Scrollable { public scrollTopOffset: number = 0; private log: ReturnType; - private debug = false; + private debug = true; constructor(public el: HTMLDivElement, x = false, y = true, public splitOffset = 300, logPrefix = '', public appendTo = el, public onScrollOffset = splitOffset) { this.container = document.createElement('div'); @@ -333,6 +333,8 @@ export default class Scrollable { } public onScroll() { + this.log('onScroll call'); + if(this.onScrollMeasure) fastdom.clear(this.onScrollMeasure); this.onScrollMeasure = fastdom.measure(() => { // @ts-ignore quick brown fix @@ -467,6 +469,10 @@ export default class Scrollable { this.onManualScrollBottom(scrollTop, needHeight); }); } else if(this.paddings.down) { // scrolled manually or safari + if(this.debug) { + this.log.warn('seems manually scrolled bottom', this.paddings.up, this.lastScrollTop); + } + this.onManualScrollBottom(scrollTop, needHeight); } } else { // scrolling top @@ -496,6 +502,10 @@ export default class Scrollable { this.onManualScrollTop(scrollTop, needHeight, maxScrollTop); }); } else if(this.paddings.up) { + if(this.debug) { + this.log.warn('seems manually scrolled top', this.paddings.down, this.lastScrollTop); + } + this.onManualScrollTop(scrollTop, needHeight, maxScrollTop); } } @@ -510,11 +520,11 @@ export default class Scrollable { }); this.onScrollMeasure.then(({value, maxValue}) => { - fastdom.mutate(() => { + //fastdom.mutate(() => { // @ts-ignore //this.thumb.style[this.side] = (value >= maxValue ? maxValue : value) + '%'; this.thumb.style.transform = this.translate + '(' + (value >= maxValue ? maxValue : value) + 'px)'; - }); + //}); }); //console.timeEnd('scroll onScroll'); @@ -536,6 +546,7 @@ export default class Scrollable { this.log.warn('bait it off now', this, length, this.splitUp.childElementCount, scrollTop, this.paddings.up, h); } + this.paddingTopDiv.style.height = this.paddings.up + 'px'; this.paddingBottomDiv.style.height = this.paddings.down + 'px'; this.onTopIntersection((this.size * 2) + (needHeight * 2)); }); @@ -558,6 +569,7 @@ export default class Scrollable { } this.paddingTopDiv.style.height = this.paddings.up + 'px'; + this.paddingBottomDiv.style.height = this.paddings.down + 'px'; this.onBottomIntersection(this.size + (needHeight * 2)); }); } diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts index fb31d380..ec41d0e0 100644 --- a/src/components/wrappers.ts +++ b/src/components/wrappers.ts @@ -431,12 +431,12 @@ export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement { return div; } -export function wrapPhoto(this: AppImManager, photo: any, message: any, container: HTMLDivElement) { +export function wrapPhoto(this: AppImManager, photo: any, message: any, container: HTMLDivElement, boxWidth = 380, boxHeight = 380) { //container.classList.add('photo'); let peerID = this.peerID; - let size = appPhotosManager.setAttachmentSize(photo.id, container); + let size = appPhotosManager.setAttachmentSize(photo.id, container, boxWidth, boxHeight); let image = container.firstElementChild as HTMLImageElement || new Image(); //let size = appPhotosManager.setAttachmentSize(photo.id, image); image.setAttribute('message-id', message.mid); diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index df4f5434..623c51b1 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -34,6 +34,8 @@ export class AppDialogsManager { public domsArchived: {[peerID: number]: DialogDom} = {}; public lastActiveListElement: HTMLElement = null; + public savedAvatarURLs: {[peerID: number]: string} = {}; + constructor() { this.pinnedDelimiter = document.createElement('div'); this.pinnedDelimiter.classList.add('pinned-delimiter'); @@ -86,10 +88,11 @@ export class AppDialogsManager { }); } - public async loadDialogPhoto(div: HTMLDivElement, peerID: number | string, isDialog = false): Promise { + // peerID == peerID || title + public async loadDialogPhoto(div: HTMLDivElement, peerID: number, isDialog = false, title = ''): Promise { let inputPeer: any; let location: any; - if(typeof(peerID) != 'string') { + if(peerID) { inputPeer = appPeersManager.getInputPeerByID(peerID); location = appPeersManager.getPeerPhoto(peerID); } @@ -113,7 +116,7 @@ export class AppDialogsManager { } let color = ''; - if(typeof(peerID) != 'string' && peerID != this.myID) { + if(peerID && peerID != this.myID) { color = appPeersManager.getPeerColorByID(peerID); } @@ -121,7 +124,7 @@ export class AppDialogsManager { div.style.fontSize = ''; div.style.backgroundColor = color; - let abbrSplitted = (typeof(peerID) != 'string' ? appPeersManager.getPeerTitle(peerID, true) : peerID).split(' '); + let abbrSplitted = (!title && peerID ? appPeersManager.getPeerTitle(peerID, true) : title).split(' '); let abbr = (abbrSplitted.length == 2 ? abbrSplitted[0][0] + abbrSplitted[1][0] : abbrSplitted[0][0]).toUpperCase(); @@ -135,17 +138,21 @@ export class AppDialogsManager { return true; } - let res = await apiFileManager.downloadSmallFile({ - _: 'inputPeerPhotoFileLocation', - dc_id: location.dc_id, - flags: 0, - peer: inputPeer, - volume_id: location.photo_small.volume_id, - local_id: location.photo_small.local_id - }); + if(!this.savedAvatarURLs[peerID]) { + let res = await apiFileManager.downloadSmallFile({ + _: 'inputPeerPhotoFileLocation', + dc_id: location.dc_id, + flags: 0, + peer: inputPeer, + volume_id: location.photo_small.volume_id, + local_id: location.photo_small.local_id + }); + + this.savedAvatarURLs[peerID] = URL.createObjectURL(res); + } let img = new Image(); - img.src = URL.createObjectURL(res); + img.src = this.savedAvatarURLs[peerID]; div.innerHTML = ''; div.style.fontSize = '0'; // need div.append(img); diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index 407b076f..2f71d104 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -132,7 +132,7 @@ class BubbleGroups { this.groups.push(group = [bubble]); } - console.log('addBubble', bubble, message.mid, fromID, reverse, group); + //console.log('addBubble', bubble, message.mid, fromID, reverse, group); this.bubblesByGroups[reverse ? 'unshift' : 'push']({timestamp, fromID, mid: message.mid, group}); this.updateGroup(group); @@ -153,7 +153,7 @@ class BubbleGroups { let first = group[0]; - console.log('updateGroup', group, first); + //console.log('updateGroup', group, first); if(group.length == 1) { first.classList.add('is-group-first', 'is-group-last'); @@ -705,6 +705,7 @@ export class AppImManager { if(dialog) { this.setPeer(this.peerID, dialog.top_message); } else { + this.log('will scroll down 3'); this.scroll.scrollTop = this.scroll.scrollHeight; } }); @@ -877,7 +878,7 @@ export class AppImManager { } }); - lottieLoader.checkAnimations(); + lottieLoader.checkAnimations(false, 'chat'); if(readed.length) { let max = Math.max(...readed); @@ -903,8 +904,10 @@ export class AppImManager { } public setScroll() { - this.scrollable = new Scrollable(this.bubblesContainer, false, true, 750, 'IM', this.chatInner/* 1500 */, 300); + this.scrollable = new Scrollable(this.bubblesContainer, false, true, 750, 'IM', this.chatInner/* 1500 */, 450); this.scroll = this.scrollable.container; + + this.bubblesContainer.append(this.goDownBtn); this.scrollable.setVirtualContainer(this.chatInner); this.scrollable.onScrolledTop = () => this.loadMoreHistory(true); @@ -1062,6 +1065,7 @@ export class AppImManager { let dialog = appMessagesManager.getDialogByPeerID(peerID)[0]; if(dialog && lastMsgID == dialog.top_message) { + this.log('will scroll down', this.scroll.scrollTop, this.scroll.scrollHeight); this.scroll.scrollTop = this.scroll.scrollHeight; } else { //this.bubbles[lastMsgID].scrollIntoView(); @@ -1086,7 +1090,7 @@ export class AppImManager { this.pinnedMessageContainer.style.display = 'none'; - this.preloader.attach(this.chatInner); + this.preloader.attach(this.bubblesContainer); let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0] || null; //////this.log('setPeer peerID:', this.peerID, dialog, lastMsgID); @@ -1119,7 +1123,7 @@ export class AppImManager { this.titleEl.innerHTML = appSidebarRight.profileElements.name.innerHTML = title; this.topbar.style.display = this.goDownBtn.style.display = ''; - appSidebarRight.toggleSidebar(true); + //appSidebarRight.toggleSidebar(true); this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : ''; @@ -1148,6 +1152,7 @@ export class AppImManager { if(bubble) this.bubbles[lastMsgID].scrollIntoView(); else this.log.warn('no bubble by lastMsgID:', lastMsgID); } else { + this.log('will scroll down 2'); this.scroll.scrollTop = this.scroll.scrollHeight; } } else if(dialog && dialog.top_message) { // add last message, bc in getHistory will load < max_id @@ -1183,6 +1188,7 @@ export class AppImManager { } this.log.error('setPeer promises error:', err); + this.preloader.detach(); return false; }); } @@ -1497,7 +1503,7 @@ export class AppImManager { bubble.classList.add('photo'); //appPhotosManager.savePhoto(webpage.photo); // hot-fix because no webpage manager - wrapPhoto.call(this, webpage.photo, message, preview); + wrapPhoto.call(this, webpage.photo, message, preview, 380, 300); } if(preview) { @@ -1688,7 +1694,7 @@ export class AppImManager { } else if(!title && message.fwd_from && message.fwd_from.from_name) { title = message.fwd_from.from_name; - appDialogsManager.loadDialogPhoto(avatarDiv, title); + appDialogsManager.loadDialogPhoto(avatarDiv, 0, false, title); } avatarDiv.dataset.peerID = message.fromID; @@ -1824,12 +1830,20 @@ export class AppImManager { if(!isBackLimit) { this.scrollPosition.prepareFor(reverse ? 'up' : 'down'); } - - /* for(let i = 0; i < 25; ++i) */ history.forEachReverse((msgID: number) => { - let message = appMessagesManager.getMessage(msgID); - - this.renderMessage(message, reverse, true); - }); + + if(testScroll) { + for(let i = 0; i < 25; ++i) history.forEachReverse((msgID: number) => { + let message = appMessagesManager.getMessage(msgID); + + this.renderMessage(message, reverse, true); + }); + } else { + history.forEachReverse((msgID: number) => { + let message = appMessagesManager.getMessage(msgID); + + this.renderMessage(message, reverse, true); + }); + } if(!isBackLimit) { this.scrollPosition.restore(); diff --git a/src/lib/appManagers/appMediaViewer.ts b/src/lib/appManagers/appMediaViewer.ts index 0fd8a2e5..9b7c1e92 100644 --- a/src/lib/appManagers/appMediaViewer.ts +++ b/src/lib/appManagers/appMediaViewer.ts @@ -52,6 +52,10 @@ export class AppMediaViewer { this.buttons.close.addEventListener('click', () => { //this.overlaysDiv.classList.remove('active'); this.content.container.innerHTML = ''; + if(this.content.container.firstElementChild) { + URL.revokeObjectURL((this.content.container.firstElementChild as HTMLImageElement).src); + } + this.currentMessageID = 0; this.setMoverToTarget(this.lastTarget, true); diff --git a/src/lib/appManagers/appSidebarRight.ts b/src/lib/appManagers/appSidebarRight.ts index 79c85023..af646e26 100644 --- a/src/lib/appManagers/appSidebarRight.ts +++ b/src/lib/appManagers/appSidebarRight.ts @@ -87,6 +87,8 @@ class AppSidebarRight { private mediaDivsByIDs: { [mid: number]: HTMLDivElement } = {}; + + public urlsToRevoke: string[] = []; constructor() { let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement; @@ -212,7 +214,7 @@ class AppSidebarRight { } public loadSidebarMedia(single = false) { - if(testScroll /* || 1 == 1 */) { + if(testScroll/* || 1 == 1 */) { return; } @@ -298,14 +300,17 @@ class AppSidebarRight { //this.log('inputMessagesFilterPhotoVideo', message, media); - let load = () => appPhotosManager.preloadPhoto(media, appPhotosManager.choosePhotoSize(media, 380, 0)) + let load = () => appPhotosManager.preloadPhoto(media, appPhotosManager.choosePhotoSize(media, 200, 200)) .then((blob) => { if($rootScope.selectedPeerID != peerID) { this.log.warn('peer changed'); return; } + + let url = URL.createObjectURL(blob); + this.urlsToRevoke.push(url); - div.style.backgroundImage = 'url(' + URL.createObjectURL(blob) + ')'; + div.style.backgroundImage = 'url(' + url + ')'; }); div.setAttribute('message-id', '' + message.mid); @@ -372,8 +377,11 @@ class AppSidebarRight { this.log.warn('peer changed'); return; } + + let url = URL.createObjectURL(blob); + this.urlsToRevoke.push(url); - previewDiv.style.backgroundImage = 'url(' + URL.createObjectURL(blob) + ')'; + previewDiv.style.backgroundImage = 'url(' + url + ')'; }); this.lazyLoadQueueSidebar.push({div: previewDiv, load}); @@ -475,6 +483,11 @@ class AppSidebarRight { putPreloader(parent, true); } }); + + this.urlsToRevoke.forEach(url => { + URL.revokeObjectURL(url); + }); + this.urlsToRevoke.length = 0; this.sharedMediaTypes.forEach(type => { //this.minMediaID[type] = 0; diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss index 165d6439..7f6fcebc 100644 --- a/src/scss/partials/_chat.scss +++ b/src/scss/partials/_chat.scss @@ -113,7 +113,16 @@ position: relative; > .scrollable { - position: unset; + //position: unset; + + height: auto; + position: absolute; + bottom: 0; + left: 0; + + /* display: flex; + flex-direction: column; + justify-content: flex-end; */ } &:not(.scrolled-down) { @@ -141,10 +150,10 @@ display: flex; flex-direction: column; flex-shrink: 1; - padding-top: 9px; + //padding-top: 9px; margin: 0 auto; box-sizing: border-box; - min-height: 100%; + /* min-height: 100%; */ justify-content: flex-end; &.is-chat { @@ -469,7 +478,8 @@ font-size: .95rem; // margin: .25rem; margin: 4px 4px 4px 6px; - padding: .25rem; + //padding: .25rem; + padding: 4px; margin-bottom: -5px; border-radius: 4px; //transition: anim(background-color); @@ -592,6 +602,7 @@ max-width: 100%; color: #000; line-height: 21px; + word-break: break-word; * { overflow: hidden; diff --git a/src/scss/partials/_rightSIdebar.scss b/src/scss/partials/_rightSIdebar.scss index 3293c30d..be3a0c54 100644 --- a/src/scss/partials/_rightSIdebar.scss +++ b/src/scss/partials/_rightSIdebar.scss @@ -33,6 +33,7 @@ flex: 1 1 auto; display: flex; flex-direction: column; + height: 100%; .profile-name { text-align: center; @@ -106,11 +107,17 @@ margin-left: -54px; } + &-wrapper { + flex: 0 0 auto; + } + .content-container { width: 100%; max-width: 100%; - overflow: hidden; - flex: 1; + //overflow: hidden; + flex: 1 1 auto; + position: relative; + //height: 1%; // fix safari } .profile-tabs { @@ -118,7 +125,8 @@ } .profile-tabs-content { - height: 100%; + min-height: 100%; + position: absolute; // FIX THE SAFARI! /* width: 500%; margin-left: -100%; */ @@ -131,7 +139,7 @@ } */ > div { - height: 100%; + //height: 100%; position: relative; }