|
|
|
@ -27,21 +27,35 @@ console.log('appImManager included!');
@@ -27,21 +27,35 @@ console.log('appImManager included!');
|
|
|
|
|
let testScroll = false; |
|
|
|
|
|
|
|
|
|
class ScrollPosition { |
|
|
|
|
public previousScrollHeightMinusTop = 0; |
|
|
|
|
public readyFor = 'up'; |
|
|
|
|
public container: HTMLElement; |
|
|
|
|
previousScrollHeightMinusTop = 0; |
|
|
|
|
readyFor = 'up'; |
|
|
|
|
container: HTMLElement; |
|
|
|
|
rAF: number; |
|
|
|
|
debug = true; |
|
|
|
|
|
|
|
|
|
constructor(public node: HTMLElement) { |
|
|
|
|
constructor(node: HTMLElement) { |
|
|
|
|
this.container = node.parentElement; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public restore() { |
|
|
|
|
//console.log('scrollPosition restore 2', this.node.scrollHeight, (this.node.scrollHeight
|
|
|
|
|
//- this.previousScrollHeightMinusTop) + 'px', this.container);
|
|
|
|
|
restore() { |
|
|
|
|
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' || appImManager.scroll.parentElement.classList.contains('scrolled-down')) { |
|
|
|
|
this.container.scrollTop = this.node.scrollHeight |
|
|
|
|
- this.previousScrollHeightMinusTop; |
|
|
|
|
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; |
|
|
|
|
}); |
|
|
|
|
} 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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 'down' doesn't need to be special cased unless the
|
|
|
|
@ -50,12 +64,130 @@ class ScrollPosition {
@@ -50,12 +64,130 @@ class ScrollPosition {
|
|
|
|
|
// a Facebook messages effect
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public prepareFor(direction: string) { |
|
|
|
|
this.readyFor = direction || 'up'; |
|
|
|
|
this.previousScrollHeightMinusTop = this.node.scrollHeight |
|
|
|
|
- this.container.scrollTop; |
|
|
|
|
prepareFor(direction = 'up') { |
|
|
|
|
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.trace('scrollPosition prepareFor', direction, this.container.scrollHeight, |
|
|
|
|
this.container.scrollTop, this.previousScrollHeightMinusTop); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class BubbleGroups { |
|
|
|
|
bubblesByGroups: Array<{timestamp: number, fromID: number, mid: number, group: HTMLDivElement[]}> = []; // map to group
|
|
|
|
|
groups: Array<HTMLDivElement[]> = []; |
|
|
|
|
updateRAFs: Map<HTMLDivElement[], number> = new Map(); |
|
|
|
|
newGroupDiff = 120; |
|
|
|
|
|
|
|
|
|
removeBubble(bubble: HTMLDivElement, mid: number) { |
|
|
|
|
let details = this.bubblesByGroups.findAndSplice(g => g.mid == mid); |
|
|
|
|
if(details && details.group.length) { |
|
|
|
|
details.group.findAndSplice(d => d == bubble); |
|
|
|
|
if(!details.group.length) { |
|
|
|
|
this.groups.findAndSplice(g => g == details.group); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addBubble(bubble: HTMLDivElement, message: any, reverse: boolean) { |
|
|
|
|
let timestamp = message.date; |
|
|
|
|
let fromID = message.fromID; |
|
|
|
|
let group: HTMLDivElement[]; |
|
|
|
|
|
|
|
|
|
// try to find added
|
|
|
|
|
//this.removeBubble(message.mid);
|
|
|
|
|
|
|
|
|
|
if(this.bubblesByGroups.length) { |
|
|
|
|
if(reverse) { |
|
|
|
|
let g = this.bubblesByGroups[0]; |
|
|
|
|
if(g.fromID == fromID && (g.timestamp - timestamp) < this.newGroupDiff) { |
|
|
|
|
group = g.group; |
|
|
|
|
group.unshift(bubble); |
|
|
|
|
} else { |
|
|
|
|
this.groups.unshift(group = [bubble]); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
let g = this.bubblesByGroups[this.bubblesByGroups.length - 1]; |
|
|
|
|
if(g.fromID == fromID && (timestamp - g.timestamp) < this.newGroupDiff) { |
|
|
|
|
group = g.group; |
|
|
|
|
group.push(bubble); |
|
|
|
|
} else { |
|
|
|
|
this.groups.push(group = [bubble]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
this.groups.push(group = [bubble]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
console.log('addBubble', bubble, message.mid, fromID, reverse, group); |
|
|
|
|
|
|
|
|
|
//console.log('scrollPosition prepareFor', direction, this.node.scrollHeight, this.previousScrollHeightMinusTop + 'px')
|
|
|
|
|
this.bubblesByGroups[reverse ? 'unshift' : 'push']({timestamp, fromID, mid: message.mid, group}); |
|
|
|
|
this.updateGroup(group); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
updateGroup(group: HTMLDivElement[]) { |
|
|
|
|
if(this.updateRAFs.has(group)) { |
|
|
|
|
window.cancelAnimationFrame(this.updateRAFs.get(group)); |
|
|
|
|
this.updateRAFs.delete(group); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.updateRAFs.set(group, window.requestAnimationFrame(() => { |
|
|
|
|
this.updateRAFs.delete(group); |
|
|
|
|
|
|
|
|
|
if(!group.length) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let first = group[0]; |
|
|
|
|
|
|
|
|
|
console.log('updateGroup', group, first); |
|
|
|
|
|
|
|
|
|
if(group.length == 1) { |
|
|
|
|
first.classList.add('is-group-first', 'is-group-last'); |
|
|
|
|
return; |
|
|
|
|
} else { |
|
|
|
|
first.classList.remove('is-group-last'); |
|
|
|
|
first.classList.add('is-group-first'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let length = group.length - 1; |
|
|
|
|
for(let i = 1; i < length; ++i) { |
|
|
|
|
let bubble = group[i]; |
|
|
|
|
bubble.classList.remove('is-group-last', 'is-group-first'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let last = group[group.length - 1]; |
|
|
|
|
last.classList.remove('is-group-first'); |
|
|
|
|
last.classList.add('is-group-last'); |
|
|
|
|
})); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
updateGroupByMessageID(mid: number) { |
|
|
|
|
let details = this.bubblesByGroups.find(g => g.mid == mid); |
|
|
|
|
if(details) { |
|
|
|
|
this.updateGroup(details.group); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cleanup() { |
|
|
|
|
this.bubblesByGroups = []; |
|
|
|
|
for(let value of this.updateRAFs.values()) { |
|
|
|
|
window.cancelAnimationFrame(value); |
|
|
|
|
} |
|
|
|
|
this.updateRAFs.clear(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -128,6 +260,8 @@ export class AppImManager {
@@ -128,6 +260,8 @@ export class AppImManager {
|
|
|
|
|
|
|
|
|
|
private setPeerPromise: Promise<boolean> = null; |
|
|
|
|
|
|
|
|
|
public bubbleGroups = new BubbleGroups(); |
|
|
|
|
|
|
|
|
|
constructor() { |
|
|
|
|
this.log = logger('IM'); |
|
|
|
|
|
|
|
|
@ -152,12 +286,14 @@ export class AppImManager {
@@ -152,12 +286,14 @@ export class AppImManager {
|
|
|
|
|
this.myID = userAuth ? userAuth.id : 0; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// will call when message is sent (only 1)
|
|
|
|
|
$rootScope.$on('history_append', (e: CustomEvent) => { |
|
|
|
|
let details = e.detail; |
|
|
|
|
|
|
|
|
|
this.renderMessagesByIDs([details.messageID]); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// will call when sent for update pos
|
|
|
|
|
$rootScope.$on('history_update', (e: CustomEvent) => { |
|
|
|
|
let details = e.detail; |
|
|
|
|
|
|
|
|
@ -169,6 +305,7 @@ export class AppImManager {
@@ -169,6 +305,7 @@ export class AppImManager {
|
|
|
|
|
|
|
|
|
|
let message = appMessagesManager.getMessage(mid); |
|
|
|
|
//this.log('history_update', this.bubbles[mid], mid, message);
|
|
|
|
|
|
|
|
|
|
this.renderMessage(message, false, false, bubble); |
|
|
|
|
|
|
|
|
|
this.deleteEmptySideDivs(); |
|
|
|
@ -219,6 +356,8 @@ export class AppImManager {
@@ -219,6 +356,8 @@ export class AppImManager {
|
|
|
|
|
bubble.classList.remove('is-sending'); |
|
|
|
|
bubble.classList.add('is-sent'); |
|
|
|
|
|
|
|
|
|
this.bubbleGroups.removeBubble(bubble, tempID); |
|
|
|
|
|
|
|
|
|
delete this.bubbles[tempID]; |
|
|
|
|
} else { |
|
|
|
|
this.log.warn('message_sent there is no bubble', e.detail); |
|
|
|
@ -363,9 +502,7 @@ export class AppImManager {
@@ -363,9 +502,7 @@ export class AppImManager {
|
|
|
|
|
let ids = Object.keys(this.bubbles).map(k => +k).filter(id => { |
|
|
|
|
let message = appMessagesManager.getMessage(id); |
|
|
|
|
|
|
|
|
|
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 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))); |
|
|
|
|
}).sort(); |
|
|
|
|
let idx = ids.findIndex(i => i == messageID); |
|
|
|
|
|
|
|
|
@ -458,8 +595,7 @@ export class AppImManager {
@@ -458,8 +595,7 @@ export class AppImManager {
|
|
|
|
|
|
|
|
|
|
if(!msgID) return; |
|
|
|
|
|
|
|
|
|
if(this.myID == this.peerID || |
|
|
|
|
(this.peerID < 0 && !appPeersManager.isChannel(this.peerID) && !appPeersManager.isMegagroup(this.peerID))) { |
|
|
|
|
if(this.myID == this.peerID || (this.peerID < 0 && !appPeersManager.isChannel(this.peerID) && !appPeersManager.isMegagroup(this.peerID))) { |
|
|
|
|
this.contextMenuPin.style.display = ''; |
|
|
|
|
} else this.contextMenuPin.style.display = 'none'; |
|
|
|
|
|
|
|
|
@ -646,40 +782,8 @@ export class AppImManager {
@@ -646,40 +782,8 @@ export class AppImManager {
|
|
|
|
|
this.loadMediaQueueProcess(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public async loadMediaQueueProcessOld(): Promise<void[]> { |
|
|
|
|
if(this.loadMediaQueuePromise /* || 1 == 1 */) return this.loadMediaQueuePromise; |
|
|
|
|
|
|
|
|
|
let woo = this.loadMediaQueue.splice(-5, 5).reverse().map(f => f()); |
|
|
|
|
|
|
|
|
|
if(woo.length) { |
|
|
|
|
///this.log('Will load more media:', woo.length);
|
|
|
|
|
|
|
|
|
|
woo.forEach(async(promise) => { |
|
|
|
|
try { |
|
|
|
|
await promise; |
|
|
|
|
} catch(err) { |
|
|
|
|
this.log.error('loadMediaQueue error:', err); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.loadingMedia--; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
this.loadMediaQueuePromise = Promise.all(woo); |
|
|
|
|
await this.loadMediaQueuePromise; |
|
|
|
|
} catch(err) { |
|
|
|
|
this.log.error('loadMediaQueue error:', err); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.loadMediaQueuePromise = null; |
|
|
|
|
|
|
|
|
|
if(this.loadMediaQueue.length) return this.loadMediaQueueProcess(); |
|
|
|
|
return this.loadMediaQueuePromise; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public async loadMediaQueueProcess(): Promise<void[]> { |
|
|
|
|
if(this.loadingMedia >= 5) return; |
|
|
|
|
if(this.loadingMedia >= 5/* || 1 == 1 */) return; |
|
|
|
|
|
|
|
|
|
let item = this.loadMediaQueue.pop(); |
|
|
|
|
if(item) { |
|
|
|
@ -709,44 +813,10 @@ export class AppImManager {
@@ -709,44 +813,10 @@ export class AppImManager {
|
|
|
|
|
return apiManager.invokeApi('account.updateStatus', {offline: this.offline}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public onScroll() { |
|
|
|
|
let readed: number[] = []; |
|
|
|
|
|
|
|
|
|
this.unreaded.forEachReverse((msgID, idx) => { |
|
|
|
|
let bubble = this.bubbles[msgID]; |
|
|
|
|
|
|
|
|
|
if(isElementInViewport(bubble)) { |
|
|
|
|
readed.push(msgID); |
|
|
|
|
this.unreaded.splice(idx, 1); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
lottieLoader.checkAnimations(); |
|
|
|
|
|
|
|
|
|
if(readed.length) { |
|
|
|
|
let max = Math.max(...readed); |
|
|
|
|
let min = Math.min(...readed); |
|
|
|
|
|
|
|
|
|
if(this.peerID < 0) { |
|
|
|
|
max = appMessagesIDsManager.getMessageIDInfo(max)[0]; |
|
|
|
|
min = appMessagesIDsManager.getMessageIDInfo(min)[0]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//appMessagesManager.readMessages(readed);
|
|
|
|
|
appMessagesManager.readHistory(this.peerID, max, min).catch((err: any) => { |
|
|
|
|
this.log.error('readHistory err:', err); |
|
|
|
|
appMessagesManager.readHistory(this.peerID, max, min); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(this.scroll.scrollHeight - (this.scroll.scrollTop + this.scroll.offsetHeight) == 0/* <= 5 */) { |
|
|
|
|
this.scroll.parentElement.classList.add('scrolled-down'); |
|
|
|
|
} else if(this.scroll.parentElement.classList.contains('scrolled-down')) { |
|
|
|
|
this.scroll.parentElement.classList.remove('scrolled-down'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public loadMoreHistory(top: boolean) { |
|
|
|
|
// load more history
|
|
|
|
|
if(!this.getHistoryPromise && !this.getHistoryTimeout && !testScroll) { |
|
|
|
|
// возможно нужно добавить разные таймауты для верха и низа
|
|
|
|
|
if(!this.getHistoryPromise && !this.getHistoryTimeout && this.peerID && !testScroll) { |
|
|
|
|
this.getHistoryTimeout = setTimeout(() => { // must be
|
|
|
|
|
let history = Object.keys(this.bubbles).map(id => +id).sort(); |
|
|
|
|
|
|
|
|
@ -765,32 +835,13 @@ export class AppImManager {
@@ -765,32 +835,13 @@ export class AppImManager {
|
|
|
|
|
|
|
|
|
|
this.getHistoryTimeout = 0; |
|
|
|
|
|
|
|
|
|
let willLoad = false; |
|
|
|
|
if(!this.scrolledAll) { |
|
|
|
|
let length = history.length < 10 ? history.length : 10; |
|
|
|
|
for(let i = 0; i < length; ++i) { |
|
|
|
|
let msgID = history[i]; |
|
|
|
|
|
|
|
|
|
let bubble = this.bubbles[msgID]; |
|
|
|
|
|
|
|
|
|
if(!bubble) { |
|
|
|
|
this.log.error('no bubble by msgID:', msgID); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(isElementInViewport(bubble)) { |
|
|
|
|
willLoad = true; |
|
|
|
|
|
|
|
|
|
////this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history, bubble);
|
|
|
|
|
if(!this.scrolledAll && top) { |
|
|
|
|
this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history); |
|
|
|
|
/* false && */!testScroll && this.getHistory(history[0], true).then(() => { // uncomment
|
|
|
|
|
this.onScroll(); |
|
|
|
|
}).catch(err => { |
|
|
|
|
this.log.warn('Could not load more history, err:', err); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(this.scrolledAllDown) return; |
|
|
|
@ -802,34 +853,62 @@ export class AppImManager {
@@ -802,34 +853,62 @@ export class AppImManager {
|
|
|
|
|
} */ |
|
|
|
|
|
|
|
|
|
// if scroll down after search
|
|
|
|
|
if(!willLoad && (!dialog || history.indexOf(dialog.top_message) === -1)) { |
|
|
|
|
let lastMsgIDs = history.slice(-10); |
|
|
|
|
for(let msgID of lastMsgIDs) { |
|
|
|
|
let bubble = this.bubbles[msgID]; |
|
|
|
|
|
|
|
|
|
if(isElementInViewport(bubble)) { |
|
|
|
|
willLoad = true; |
|
|
|
|
|
|
|
|
|
////this.log('Will load more (down) history by maxID:', lastMsgIDs[lastMsgIDs.length - 1], lastMsgIDs, bubble);
|
|
|
|
|
/* false && */!testScroll && this.getHistory(lastMsgIDs[lastMsgIDs.length - 1], false, true).then(() => { // uncomment
|
|
|
|
|
if(!top && (!dialog || history.indexOf(dialog.top_message) === -1)) { |
|
|
|
|
this.log('Will load more (down) history by maxID:', history[history.length - 1], history); |
|
|
|
|
/* false && */!testScroll && this.getHistory(history[history.length - 1], false, true).then(() => { // uncomment
|
|
|
|
|
this.onScroll(); |
|
|
|
|
}).catch(err => { |
|
|
|
|
this.log.warn('Could not load more history, err:', err); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}, 0); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
public onScroll() { |
|
|
|
|
let readed: number[] = []; |
|
|
|
|
|
|
|
|
|
this.unreaded.forEachReverse((msgID, idx) => { |
|
|
|
|
let bubble = this.bubbles[msgID]; |
|
|
|
|
|
|
|
|
|
if(isElementInViewport(bubble)) { |
|
|
|
|
readed.push(msgID); |
|
|
|
|
this.unreaded.splice(idx, 1); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
lottieLoader.checkAnimations(); |
|
|
|
|
|
|
|
|
|
if(readed.length) { |
|
|
|
|
let max = Math.max(...readed); |
|
|
|
|
let min = Math.min(...readed); |
|
|
|
|
|
|
|
|
|
if(this.peerID < 0) { |
|
|
|
|
max = appMessagesIDsManager.getMessageIDInfo(max)[0]; |
|
|
|
|
min = appMessagesIDsManager.getMessageIDInfo(min)[0]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//appMessagesManager.readMessages(readed);
|
|
|
|
|
appMessagesManager.readHistory(this.peerID, max, min).catch((err: any) => { |
|
|
|
|
this.log.error('readHistory err:', err); |
|
|
|
|
appMessagesManager.readHistory(this.peerID, max, min); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
|
|
if(this.scroll.scrollHeight - (this.scroll.scrollTop + this.scroll.offsetHeight) == 0/* <= 5 */) { |
|
|
|
|
this.scroll.parentElement.classList.add('scrolled-down'); |
|
|
|
|
} else if(this.scroll.parentElement.classList.contains('scrolled-down')) { |
|
|
|
|
this.scroll.parentElement.classList.remove('scrolled-down'); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public setScroll() { |
|
|
|
|
this.scrollable = new Scrollable(this.bubblesContainer, false, true, 750, 'IM'/* 1500 */); |
|
|
|
|
this.scrollable = new Scrollable(this.bubblesContainer, false, true, 750, 'IM', this.chatInner/* 1500 */, 300); |
|
|
|
|
this.scroll = this.scrollable.container; |
|
|
|
|
|
|
|
|
|
this.scrollable.setVirtualContainer(this.chatInner); |
|
|
|
|
this.scrollable.onScrolledTop = () => this.loadMoreHistory(true); |
|
|
|
|
this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false); |
|
|
|
|
|
|
|
|
|
this.scrollPosition = new ScrollPosition(this.chatInner); |
|
|
|
|
this.scroll.addEventListener('scroll', this.onScroll.bind(this)); |
|
|
|
@ -937,6 +1016,7 @@ export class AppImManager {
@@ -937,6 +1016,7 @@ export class AppImManager {
|
|
|
|
|
} |
|
|
|
|
this.bubbles = {}; |
|
|
|
|
this.dateMessages = {}; |
|
|
|
|
this.bubbleGroups.cleanup(); |
|
|
|
|
this.unreaded = []; |
|
|
|
|
this.unreadOut = []; |
|
|
|
|
this.loadMediaQueue = []; |
|
|
|
@ -984,7 +1064,8 @@ export class AppImManager {
@@ -984,7 +1064,8 @@ export class AppImManager {
|
|
|
|
|
if(dialog && lastMsgID == dialog.top_message) { |
|
|
|
|
this.scroll.scrollTop = this.scroll.scrollHeight; |
|
|
|
|
} else { |
|
|
|
|
this.bubbles[lastMsgID].scrollIntoView(); |
|
|
|
|
//this.bubbles[lastMsgID].scrollIntoView();
|
|
|
|
|
this.scrollable.scrollIntoView(this.bubbles[lastMsgID]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return Promise.resolve(true); |
|
|
|
@ -1038,7 +1119,7 @@ export class AppImManager {
@@ -1038,7 +1119,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' : ''; |
|
|
|
|
|
|
|
|
@ -1048,6 +1129,8 @@ export class AppImManager {
@@ -1048,6 +1129,8 @@ export class AppImManager {
|
|
|
|
|
this.chatInner.classList.remove('is-chat'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//this.scroll.scrollTop = this.scroll.scrollHeight;
|
|
|
|
|
|
|
|
|
|
return this.setPeerPromise = Promise.all([ |
|
|
|
|
this.getHistory(forwarding ? lastMsgID + 1 : lastMsgID).then(() => { |
|
|
|
|
////this.log('setPeer removing preloader');
|
|
|
|
@ -1068,18 +1151,18 @@ export class AppImManager {
@@ -1068,18 +1151,18 @@ export class AppImManager {
|
|
|
|
|
this.scroll.scrollTop = this.scroll.scrollHeight; |
|
|
|
|
} |
|
|
|
|
} else if(dialog && dialog.top_message) { // add last message, bc in getHistory will load < max_id
|
|
|
|
|
this.renderMessage(appMessagesManager.getMessage(dialog.top_message)); |
|
|
|
|
this.renderMessage(appMessagesManager.getMessage(dialog.top_message), false, true); |
|
|
|
|
//this.scroll.scrollTop = this.scroll.scrollHeight;
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(this.scroll) { |
|
|
|
|
this.onScroll(); |
|
|
|
|
} |
|
|
|
|
this.scrollable.onScroll(); |
|
|
|
|
|
|
|
|
|
this.preloader.detach(); |
|
|
|
|
|
|
|
|
|
//setTimeout(() => {
|
|
|
|
|
//appSidebarRight.fillProfileElements();
|
|
|
|
|
appSidebarRight.loadSidebarMedia(); |
|
|
|
|
appSidebarRight.loadSidebarMedia(true); |
|
|
|
|
//}, 500);
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
@ -1123,7 +1206,6 @@ export class AppImManager {
@@ -1123,7 +1206,6 @@ export class AppImManager {
|
|
|
|
|
|
|
|
|
|
///////this.log('updateUnreadByDialog', maxID, dialog, this.unreadOut);
|
|
|
|
|
|
|
|
|
|
let length = this.unreadOut.length; |
|
|
|
|
this.unreadOut.forEachReverse((msgID, idx) => { |
|
|
|
|
if(msgID > 0 && msgID <= maxID) { |
|
|
|
|
let bubble = this.bubbles[msgID]; |
|
|
|
@ -1148,13 +1230,9 @@ export class AppImManager {
@@ -1148,13 +1230,9 @@ export class AppImManager {
|
|
|
|
|
if(!(id in this.bubbles)) return; |
|
|
|
|
|
|
|
|
|
let bubble = this.bubbles[id]; |
|
|
|
|
let parent = bubble.parentNode as HTMLDivElement; |
|
|
|
|
delete this.bubbles[id]; |
|
|
|
|
bubble.remove(); |
|
|
|
|
|
|
|
|
|
if(!parent.childNodes.length) { |
|
|
|
|
parent.remove(); |
|
|
|
|
} |
|
|
|
|
this.scrollable.removeElement(bubble); |
|
|
|
|
//bubble.remove();
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
lottieLoader.checkAnimations(); |
|
|
|
@ -1210,11 +1288,36 @@ export class AppImManager {
@@ -1210,11 +1288,36 @@ export class AppImManager {
|
|
|
|
|
//bubble.innerHTML = '';
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(message._ == 'messageService') { |
|
|
|
|
bubble.className = 'bubble service'; |
|
|
|
|
|
|
|
|
|
let action = message.action; |
|
|
|
|
|
|
|
|
|
let title = appPeersManager.getPeerTitle(message.fromID); |
|
|
|
|
let name = document.createElement('div'); |
|
|
|
|
name.classList.add('name'); |
|
|
|
|
name.dataset.peerID = message.fromID; |
|
|
|
|
name.innerHTML = title; |
|
|
|
|
|
|
|
|
|
let _ = action._; |
|
|
|
|
if(_ == "messageActionPhoneCall") { |
|
|
|
|
_ += '.' + action.type; |
|
|
|
|
} |
|
|
|
|
// @ts-ignore
|
|
|
|
|
let str = (name.innerText ? name.outerHTML + ' ' : '') + langPack[_]; |
|
|
|
|
bubbleContainer.innerHTML = `<div class="service-msg">${str}</div>`; |
|
|
|
|
|
|
|
|
|
if(!multipleRender) { |
|
|
|
|
this.scrollPosition.restore(); // лагает из-за этого
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// time section
|
|
|
|
|
|
|
|
|
|
let date = new Date(message.date * 1000); |
|
|
|
|
let time = ('0' + date.getHours()).slice(-2) + |
|
|
|
|
':' + ('0' + date.getMinutes()).slice(-2); |
|
|
|
|
let time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2); |
|
|
|
|
|
|
|
|
|
if(message.views) { |
|
|
|
|
bubble.classList.add('channel-post'); |
|
|
|
@ -1461,7 +1564,7 @@ export class AppImManager {
@@ -1461,7 +1564,7 @@ export class AppImManager {
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} else if(doc.mime_type == 'video/mp4' && doc.size <= 20e6) { |
|
|
|
|
////////this.log('never get free 2', doc);
|
|
|
|
|
this.log('never get free 2', doc); |
|
|
|
|
|
|
|
|
|
if(doc.type == 'round') { |
|
|
|
|
bubble.classList.add('round'); |
|
|
|
@ -1470,6 +1573,16 @@ export class AppImManager {
@@ -1470,6 +1573,16 @@ export class AppImManager {
|
|
|
|
|
bubble.classList.add('video'); |
|
|
|
|
wrapVideo.call(this, doc, attachmentDiv, message, true, null, false, doc.type == 'round'); |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} else if(doc.mime_type == 'audio/ogg') { |
|
|
|
|
let docDiv = wrapDocument(doc); |
|
|
|
|
|
|
|
|
|
messageDiv.classList.remove('message-empty'); |
|
|
|
|
|
|
|
|
|
bubble.classList.add('bubble-audio'); |
|
|
|
|
messageDiv.append(docDiv); |
|
|
|
|
processingWebPage = true; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} else { |
|
|
|
|
let docDiv = wrapDocument(doc); |
|
|
|
@ -1513,13 +1626,8 @@ export class AppImManager {
@@ -1513,13 +1626,8 @@ export class AppImManager {
|
|
|
|
|
if(message.savedFrom) { |
|
|
|
|
let fwd = document.createElement('div'); |
|
|
|
|
fwd.classList.add('forward'/* , 'tgico-forward' */); |
|
|
|
|
fwd.innerHTML = ` |
|
|
|
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"> |
|
|
|
|
<defs> |
|
|
|
|
<path d="M13.55 3.24L13.64 3.25L13.73 3.27L13.81 3.29L13.9 3.32L13.98 3.35L14.06 3.39L14.14 3.43L14.22 3.48L14.29 3.53L14.36 3.59L14.43 3.64L22.23 10.85L22.36 10.99L22.48 11.15L22.57 11.31L22.64 11.48L22.69 11.66L22.72 11.85L22.73 12.04L22.71 12.22L22.67 12.41L22.61 12.59L22.53 12.76L22.42 12.93L22.29 13.09L22.23 13.15L14.43 20.36L14.28 20.48L14.12 20.58L13.95 20.66L13.77 20.72L13.58 20.76L13.4 20.77L13.22 20.76L13.03 20.73L12.85 20.68L12.68 20.61L12.52 20.52L12.36 20.4L12.22 20.27L12.16 20.2L12.1 20.13L12.05 20.05L12.01 19.98L11.96 19.9L11.93 19.82L11.89 19.73L11.87 19.65L11.84 19.56L11.83 19.47L11.81 19.39L11.81 19.3L11.8 19.2L11.8 16.42L11 16.49L10.23 16.58L9.51 16.71L8.82 16.88L8.18 17.09L7.57 17.33L7.01 17.6L6.48 17.91L5.99 18.26L5.55 18.64L5.14 19.05L4.77 19.51L4.43 19.99L4.29 20.23L4.21 20.35L4.11 20.47L4 20.57L3.88 20.65L3.75 20.72L3.62 20.78L3.48 20.82L3.33 20.84L3.19 20.84L3.04 20.83L2.9 20.79L2.75 20.74L2.62 20.68L2.53 20.62L2.45 20.56L2.38 20.5L2.31 20.43L2.25 20.36L2.2 20.28L2.15 20.19L2.11 20.11L2.07 20.02L2.04 19.92L2.02 19.83L2.01 19.73L2 19.63L2.04 17.99L2.19 16.46L2.46 15.05L2.85 13.75L3.35 12.58L3.97 11.53L4.7 10.6L5.55 9.8L6.51 9.12L7.59 8.56L8.77 8.13L10.07 7.83L11.48 7.65L11.8 7.63L11.8 4.8L11.91 4.56L12.02 4.35L12.14 4.16L12.25 3.98L12.37 3.82L12.48 3.68L12.61 3.56L12.73 3.46L12.85 3.38L12.98 3.31L13.11 3.27L13.24 3.24L13.37 3.23L13.46 3.23L13.55 3.24Z" id="b13RmHDQtl"></path> |
|
|
|
|
</defs> |
|
|
|
|
<use xlink:href="#b13RmHDQtl" opacity="1" fill="#fff" fill-opacity="1"></use> |
|
|
|
|
</svg>`;
|
|
|
|
|
fwd.innerHTML = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">
|
|
|
|
|
<defs><path d="M13.55 3.24L13.64 3.25L13.73 3.27L13.81 3.29L13.9 3.32L13.98 3.35L14.06 3.39L14.14 3.43L14.22 3.48L14.29 3.53L14.36 3.59L14.43 3.64L22.23 10.85L22.36 10.99L22.48 11.15L22.57 11.31L22.64 11.48L22.69 11.66L22.72 11.85L22.73 12.04L22.71 12.22L22.67 12.41L22.61 12.59L22.53 12.76L22.42 12.93L22.29 13.09L22.23 13.15L14.43 20.36L14.28 20.48L14.12 20.58L13.95 20.66L13.77 20.72L13.58 20.76L13.4 20.77L13.22 20.76L13.03 20.73L12.85 20.68L12.68 20.61L12.52 20.52L12.36 20.4L12.22 20.27L12.16 20.2L12.1 20.13L12.05 20.05L12.01 19.98L11.96 19.9L11.93 19.82L11.89 19.73L11.87 19.65L11.84 19.56L11.83 19.47L11.81 19.39L11.81 19.3L11.8 19.2L11.8 16.42L11 16.49L10.23 16.58L9.51 16.71L8.82 16.88L8.18 17.09L7.57 17.33L7.01 17.6L6.48 17.91L5.99 18.26L5.55 18.64L5.14 19.05L4.77 19.51L4.43 19.99L4.29 20.23L4.21 20.35L4.11 20.47L4 20.57L3.88 20.65L3.75 20.72L3.62 20.78L3.48 20.82L3.33 20.84L3.19 20.84L3.04 20.83L2.9 20.79L2.75 20.74L2.62 20.68L2.53 20.62L2.45 20.56L2.38 20.5L2.31 20.43L2.25 20.36L2.2 20.28L2.15 20.19L2.11 20.11L2.07 20.02L2.04 19.92L2.02 19.83L2.01 19.73L2 19.63L2.04 17.99L2.19 16.46L2.46 15.05L2.85 13.75L3.35 12.58L3.97 11.53L4.7 10.6L5.55 9.8L6.51 9.12L7.59 8.56L8.77 8.13L10.07 7.83L11.48 7.65L11.8 7.63L11.8 4.8L11.91 4.56L12.02 4.35L12.14 4.16L12.25 3.98L12.37 3.82L12.48 3.68L12.61 3.56L12.73 3.46L12.85 3.38L12.98 3.31L13.11 3.27L13.24 3.24L13.37 3.23L13.46 3.23L13.55 3.24Z" id="b13RmHDQtl"></path></defs><use xlink:href="#b13RmHDQtl" opacity="1" fill="#fff" fill-opacity="1"></use></svg>`;
|
|
|
|
|
bubbleContainer.append(fwd); |
|
|
|
|
bubble.dataset.savedFrom = message.savedFrom; |
|
|
|
|
} |
|
|
|
@ -1568,17 +1676,9 @@ export class AppImManager {
@@ -1568,17 +1676,9 @@ export class AppImManager {
|
|
|
|
|
} else /* if(!message.reply_to_mid) */ { |
|
|
|
|
bubble.classList.add('hide-name'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//bubble.prepend(avatarDiv);
|
|
|
|
|
/* if(messageDiv.nextElementSibling) { |
|
|
|
|
bubble.insertBefore(avatarDiv, messageDiv.nextElementSibling); |
|
|
|
|
} else { */ |
|
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(!our && this.peerID < 0 && |
|
|
|
|
(!appPeersManager.isChannel(this.peerID) || appPeersManager.isMegagroup(this.peerID))) { |
|
|
|
|
if(!our && this.peerID < 0 && (!appPeersManager.isChannel(this.peerID) || appPeersManager.isMegagroup(this.peerID))) { |
|
|
|
|
let avatarDiv = document.createElement('div'); |
|
|
|
|
avatarDiv.classList.add('user-avatar'); |
|
|
|
|
|
|
|
|
@ -1599,26 +1699,6 @@ export class AppImManager {
@@ -1599,26 +1699,6 @@ export class AppImManager {
|
|
|
|
|
bubble.classList.add('hide-name'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(message._ == 'messageService') { |
|
|
|
|
bubble.className = 'bubble service'; |
|
|
|
|
|
|
|
|
|
let action = message.action; |
|
|
|
|
|
|
|
|
|
let title = appPeersManager.getPeerTitle(message.fromID); |
|
|
|
|
let name = document.createElement('div'); |
|
|
|
|
name.classList.add('name'); |
|
|
|
|
name.dataset.peerID = message.fromID; |
|
|
|
|
name.innerHTML = title; |
|
|
|
|
|
|
|
|
|
let _ = action._; |
|
|
|
|
if(_ == "messageActionPhoneCall") { |
|
|
|
|
_ += '.' + action.type; |
|
|
|
|
} |
|
|
|
|
// @ts-ignore
|
|
|
|
|
let str = (name.innerText ? name.outerHTML + ' ' : '') + langPack[_]; |
|
|
|
|
bubbleContainer.innerHTML = `<div class="service-msg">${str}</div>`; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bubble.classList.add(our ? 'is-out' : 'is-in'); |
|
|
|
|
if(updatePosition) { |
|
|
|
|
if(reverse) { |
|
|
|
@ -1627,6 +1707,8 @@ export class AppImManager {
@@ -1627,6 +1707,8 @@ export class AppImManager {
|
|
|
|
|
this.scrollable.append(bubble); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.bubbleGroups.addBubble(bubble, message, reverse); |
|
|
|
|
|
|
|
|
|
let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); |
|
|
|
|
let dateTimestamp = justDate.getTime(); |
|
|
|
|
if(!(dateTimestamp in this.dateMessages)) { |
|
|
|
@ -1640,8 +1722,7 @@ export class AppImManager {
@@ -1640,8 +1722,7 @@ export class AppImManager {
|
|
|
|
|
if(today < date) { |
|
|
|
|
str = 'Today'; |
|
|
|
|
} else { |
|
|
|
|
const months = ['January', 'February', 'March', 'April', 'May', 'June', |
|
|
|
|
'July', 'August', 'September', 'October', 'November', 'December']; |
|
|
|
|
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; |
|
|
|
|
str = justDate.getFullYear() == new Date().getFullYear() ? |
|
|
|
|
months[justDate.getMonth()] + ' ' + justDate.getDate() : |
|
|
|
|
justDate.toISOString().split('T')[0].split('-').reverse().join('.'); |
|
|
|
@ -1664,6 +1745,8 @@ export class AppImManager {
@@ -1664,6 +1745,8 @@ export class AppImManager {
|
|
|
|
|
this.scrollable.insertBefore(dateMessage.div, bubble); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
this.bubbleGroups.updateGroupByMessageID(message.mid); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* if(bubble.classList.contains('webpage')) { |
|
|
|
@ -1675,8 +1758,6 @@ export class AppImManager {
@@ -1675,8 +1758,6 @@ export class AppImManager {
|
|
|
|
|
if(!multipleRender) { |
|
|
|
|
this.scrollPosition.restore(); // лагает из-за этого
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//this.log('history msg', message);
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// reverse means scroll up
|
|
|
|
@ -1688,9 +1769,7 @@ export class AppImManager {
@@ -1688,9 +1769,7 @@ export class AppImManager {
|
|
|
|
|
maxID = dialog.top_message/* + 1 */; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let loadCount = Object.keys(this.bubbles).length > 0 ? |
|
|
|
|
20 : |
|
|
|
|
this.scrollable.container.parentElement.scrollHeight / 30 * 1.25 | 0; |
|
|
|
|
let loadCount = Object.keys(this.bubbles).length > 0 ? 20 : this.scrollable.container.parentElement.scrollHeight / 30 * 1.25 | 0; |
|
|
|
|
|
|
|
|
|
/* if(testScroll) { |
|
|
|
|
loadCount = 1; |
|
|
|
@ -1800,7 +1879,7 @@ export class AppImManager {
@@ -1800,7 +1879,7 @@ export class AppImManager {
|
|
|
|
|
peer: inputPeer |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let settings: any = { |
|
|
|
|
let settings = { |
|
|
|
|
_: 'inputPeerNotifySettings', |
|
|
|
|
flags: 0, |
|
|
|
|
mute_until: 0 |
|
|
|
@ -1850,9 +1929,7 @@ export class AppImManager {
@@ -1850,9 +1929,7 @@ export class AppImManager {
|
|
|
|
|
this.typingUsers[update.user_id] = peerID; |
|
|
|
|
|
|
|
|
|
if(!appUsersManager.hasUser(update.user_id)) { |
|
|
|
|
if(update.chat_id && |
|
|
|
|
appChatsManager.hasChat(update.chat_id) && |
|
|
|
|
!appChatsManager.isChannel(update.chat_id)) { |
|
|
|
|
if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) { |
|
|
|
|
appProfileManager.getChatFull(update.chat_id); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|