|
|
@ -27,21 +27,35 @@ console.log('appImManager included!'); |
|
|
|
let testScroll = false; |
|
|
|
let testScroll = false; |
|
|
|
|
|
|
|
|
|
|
|
class ScrollPosition { |
|
|
|
class ScrollPosition { |
|
|
|
public previousScrollHeightMinusTop = 0; |
|
|
|
previousScrollHeightMinusTop = 0; |
|
|
|
public readyFor = 'up'; |
|
|
|
readyFor = 'up'; |
|
|
|
public container: HTMLElement; |
|
|
|
container: HTMLElement; |
|
|
|
|
|
|
|
rAF: number; |
|
|
|
|
|
|
|
debug = true; |
|
|
|
|
|
|
|
|
|
|
|
constructor(public node: HTMLElement) { |
|
|
|
constructor(node: HTMLElement) { |
|
|
|
this.container = node.parentElement; |
|
|
|
this.container = node.parentElement; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public restore() { |
|
|
|
restore() { |
|
|
|
//console.log('scrollPosition restore 2', this.node.scrollHeight, (this.node.scrollHeight
|
|
|
|
let setScrollTop = this.container.scrollHeight - this.previousScrollHeightMinusTop; |
|
|
|
//- this.previousScrollHeightMinusTop) + 'px', this.container);
|
|
|
|
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')) { |
|
|
|
if(this.readyFor === 'up'/* || this.container.parentElement.classList.contains('scrolled-down') */) { |
|
|
|
this.container.scrollTop = this.node.scrollHeight |
|
|
|
if(this.debug) appImManager.log('scrollPosition restore 2', this.readyFor, this.container.scrollHeight, |
|
|
|
- this.previousScrollHeightMinusTop; |
|
|
|
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
|
|
|
|
// 'down' doesn't need to be special cased unless the
|
|
|
@ -50,12 +64,130 @@ class ScrollPosition { |
|
|
|
// a Facebook messages effect
|
|
|
|
// a Facebook messages effect
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public prepareFor(direction: string) { |
|
|
|
prepareFor(direction = 'up') { |
|
|
|
this.readyFor = direction || 'up'; |
|
|
|
if(this.rAF) { |
|
|
|
this.previousScrollHeightMinusTop = this.node.scrollHeight |
|
|
|
window.cancelAnimationFrame(this.rAF); |
|
|
|
- this.container.scrollTop; |
|
|
|
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); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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'); |
|
|
|
|
|
|
|
})); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//console.log('scrollPosition prepareFor', direction, this.node.scrollHeight, this.previousScrollHeightMinusTop + 'px')
|
|
|
|
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 { |
|
|
|
|
|
|
|
|
|
|
|
private setPeerPromise: Promise<boolean> = null; |
|
|
|
private setPeerPromise: Promise<boolean> = null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public bubbleGroups = new BubbleGroups(); |
|
|
|
|
|
|
|
|
|
|
|
constructor() { |
|
|
|
constructor() { |
|
|
|
this.log = logger('IM'); |
|
|
|
this.log = logger('IM'); |
|
|
|
|
|
|
|
|
|
|
@ -152,12 +286,14 @@ export class AppImManager { |
|
|
|
this.myID = userAuth ? userAuth.id : 0; |
|
|
|
this.myID = userAuth ? userAuth.id : 0; |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// will call when message is sent (only 1)
|
|
|
|
$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.renderMessagesByIDs([details.messageID]); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// will call when sent for update pos
|
|
|
|
$rootScope.$on('history_update', (e: CustomEvent) => { |
|
|
|
$rootScope.$on('history_update', (e: CustomEvent) => { |
|
|
|
let details = e.detail; |
|
|
|
let details = e.detail; |
|
|
|
|
|
|
|
|
|
|
@ -169,6 +305,7 @@ export class AppImManager { |
|
|
|
|
|
|
|
|
|
|
|
let message = appMessagesManager.getMessage(mid); |
|
|
|
let message = appMessagesManager.getMessage(mid); |
|
|
|
//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(); |
|
|
|
this.deleteEmptySideDivs(); |
|
|
@ -219,6 +356,8 @@ export class AppImManager { |
|
|
|
bubble.classList.remove('is-sending'); |
|
|
|
bubble.classList.remove('is-sending'); |
|
|
|
bubble.classList.add('is-sent'); |
|
|
|
bubble.classList.add('is-sent'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.bubbleGroups.removeBubble(bubble, tempID); |
|
|
|
|
|
|
|
|
|
|
|
delete this.bubbles[tempID]; |
|
|
|
delete this.bubbles[tempID]; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
this.log.warn('message_sent there is no bubble', e.detail); |
|
|
|
this.log.warn('message_sent there is no bubble', e.detail); |
|
|
@ -363,9 +502,7 @@ export class AppImManager { |
|
|
|
let ids = Object.keys(this.bubbles).map(k => +k).filter(id => { |
|
|
|
let ids = Object.keys(this.bubbles).map(k => +k).filter(id => { |
|
|
|
let message = appMessagesManager.getMessage(id); |
|
|
|
let message = appMessagesManager.getMessage(id); |
|
|
|
|
|
|
|
|
|
|
|
return message.media && (message.media.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))); |
|
|
|
|| (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(); |
|
|
|
}).sort(); |
|
|
|
let idx = ids.findIndex(i => i == messageID); |
|
|
|
let idx = ids.findIndex(i => i == messageID); |
|
|
|
|
|
|
|
|
|
|
@ -458,8 +595,7 @@ export class AppImManager { |
|
|
|
|
|
|
|
|
|
|
|
if(!msgID) return; |
|
|
|
if(!msgID) return; |
|
|
|
|
|
|
|
|
|
|
|
if(this.myID == this.peerID || |
|
|
|
if(this.myID == this.peerID || (this.peerID < 0 && !appPeersManager.isChannel(this.peerID) && !appPeersManager.isMegagroup(this.peerID))) { |
|
|
|
(this.peerID < 0 && !appPeersManager.isChannel(this.peerID) && !appPeersManager.isMegagroup(this.peerID))) { |
|
|
|
|
|
|
|
this.contextMenuPin.style.display = ''; |
|
|
|
this.contextMenuPin.style.display = ''; |
|
|
|
} else this.contextMenuPin.style.display = 'none'; |
|
|
|
} else this.contextMenuPin.style.display = 'none'; |
|
|
|
|
|
|
|
|
|
|
@ -646,40 +782,8 @@ export class AppImManager { |
|
|
|
this.loadMediaQueueProcess(); |
|
|
|
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[]> { |
|
|
|
public async loadMediaQueueProcess(): Promise<void[]> { |
|
|
|
if(this.loadingMedia >= 5) return; |
|
|
|
if(this.loadingMedia >= 5/* || 1 == 1 */) return; |
|
|
|
|
|
|
|
|
|
|
|
let item = this.loadMediaQueue.pop(); |
|
|
|
let item = this.loadMediaQueue.pop(); |
|
|
|
if(item) { |
|
|
|
if(item) { |
|
|
@ -709,6 +813,58 @@ export class AppImManager { |
|
|
|
return apiManager.invokeApi('account.updateStatus', {offline: this.offline}); |
|
|
|
return apiManager.invokeApi('account.updateStatus', {offline: this.offline}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public loadMoreHistory(top: boolean) { |
|
|
|
|
|
|
|
// load more history
|
|
|
|
|
|
|
|
// возможно нужно добавить разные таймауты для верха и низа
|
|
|
|
|
|
|
|
if(!this.getHistoryPromise && !this.getHistoryTimeout && this.peerID && !testScroll) { |
|
|
|
|
|
|
|
this.getHistoryTimeout = setTimeout(() => { // must be
|
|
|
|
|
|
|
|
let history = Object.keys(this.bubbles).map(id => +id).sort(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* let history = appMessagesManager.historiesStorage[this.peerID].history; |
|
|
|
|
|
|
|
let length = history.length; */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// filter negative ids
|
|
|
|
|
|
|
|
let lastBadIndex = -1; |
|
|
|
|
|
|
|
for(let i = 0; i < history.length; ++i) { |
|
|
|
|
|
|
|
if(history[i] <= 0) lastBadIndex = i; |
|
|
|
|
|
|
|
else break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if(lastBadIndex != -1) { |
|
|
|
|
|
|
|
history = history.slice(lastBadIndex + 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.getHistoryTimeout = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(this.scrolledAllDown) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0]; |
|
|
|
|
|
|
|
/* if(!dialog) { |
|
|
|
|
|
|
|
this.log.warn('no dialog for load history'); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if scroll down after search
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public onScroll() { |
|
|
|
public onScroll() { |
|
|
|
let readed: number[] = []; |
|
|
|
let readed: number[] = []; |
|
|
|
|
|
|
|
|
|
|
@ -744,92 +900,15 @@ export class AppImManager { |
|
|
|
} 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'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// load more history
|
|
|
|
|
|
|
|
if(!this.getHistoryPromise && !this.getHistoryTimeout && !testScroll) { |
|
|
|
|
|
|
|
this.getHistoryTimeout = setTimeout(() => { // must be
|
|
|
|
|
|
|
|
let history = Object.keys(this.bubbles).map(id => +id).sort(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* let history = appMessagesManager.historiesStorage[this.peerID].history; |
|
|
|
|
|
|
|
let length = history.length; */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// filter negative ids
|
|
|
|
|
|
|
|
let lastBadIndex = -1; |
|
|
|
|
|
|
|
for(let i = 0; i < history.length; ++i) { |
|
|
|
|
|
|
|
if(history[i] <= 0) lastBadIndex = i; |
|
|
|
|
|
|
|
else break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if(lastBadIndex != -1) { |
|
|
|
|
|
|
|
history = history.slice(lastBadIndex + 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* 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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0]; |
|
|
|
|
|
|
|
/* if(!dialog) { |
|
|
|
|
|
|
|
this.log.warn('no dialog for load history'); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
this.onScroll(); |
|
|
|
|
|
|
|
}).catch(err => { |
|
|
|
|
|
|
|
this.log.warn('Could not load more history, err:', err); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public setScroll() { |
|
|
|
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.scroll = this.scrollable.container; |
|
|
|
|
|
|
|
|
|
|
|
this.scrollable.setVirtualContainer(this.chatInner); |
|
|
|
this.scrollable.setVirtualContainer(this.chatInner); |
|
|
|
|
|
|
|
this.scrollable.onScrolledTop = () => this.loadMoreHistory(true); |
|
|
|
|
|
|
|
this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false); |
|
|
|
|
|
|
|
|
|
|
|
this.scrollPosition = new ScrollPosition(this.chatInner); |
|
|
|
this.scrollPosition = new ScrollPosition(this.chatInner); |
|
|
|
this.scroll.addEventListener('scroll', this.onScroll.bind(this)); |
|
|
|
this.scroll.addEventListener('scroll', this.onScroll.bind(this)); |
|
|
@ -886,33 +965,33 @@ export class AppImManager { |
|
|
|
let subtitle = ''; |
|
|
|
let subtitle = ''; |
|
|
|
switch(user.status._) { |
|
|
|
switch(user.status._) { |
|
|
|
case 'userStatusRecently': |
|
|
|
case 'userStatusRecently': |
|
|
|
subtitle += 'last seen recently'; |
|
|
|
subtitle += 'last seen recently'; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case 'userStatusOffline': |
|
|
|
case 'userStatusOffline': |
|
|
|
subtitle = 'last seen '; |
|
|
|
subtitle = 'last seen '; |
|
|
|
|
|
|
|
|
|
|
|
let date = user.status.was_online; |
|
|
|
let date = user.status.was_online; |
|
|
|
let now = Date.now() / 1000; |
|
|
|
let now = Date.now() / 1000; |
|
|
|
|
|
|
|
|
|
|
|
if((now - date) < 60) { |
|
|
|
if((now - date) < 60) { |
|
|
|
subtitle += ' just now'; |
|
|
|
subtitle += ' just now'; |
|
|
|
} else if((now - date) < 3600) { |
|
|
|
} else if((now - date) < 3600) { |
|
|
|
subtitle += ((now - date) / 60 | 0) + ' minutes ago'; |
|
|
|
subtitle += ((now - date) / 60 | 0) + ' minutes ago'; |
|
|
|
} else if(now - date < 86400) { |
|
|
|
} else if(now - date < 86400) { |
|
|
|
subtitle += ((now - date) / 3600 | 0) + ' hours ago'; |
|
|
|
subtitle += ((now - date) / 3600 | 0) + ' hours ago'; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
let d = new Date(date * 1000); |
|
|
|
let d = new Date(date * 1000); |
|
|
|
subtitle += ('0' + d.getDate()).slice(-2) + '.' + ('0' + (d.getMonth() + 1)).slice(-2) + ' at ' + |
|
|
|
subtitle += ('0' + d.getDate()).slice(-2) + '.' + ('0' + (d.getMonth() + 1)).slice(-2) + ' at ' + |
|
|
|
('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2); |
|
|
|
('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case 'userStatusOnline': |
|
|
|
case 'userStatusOnline': |
|
|
|
this.subtitleEl.classList.add('online'); |
|
|
|
this.subtitleEl.classList.add('online'); |
|
|
|
appSidebarRight.profileElements.subtitle.classList.add('online'); |
|
|
|
appSidebarRight.profileElements.subtitle.classList.add('online'); |
|
|
|
subtitle = 'online'; |
|
|
|
subtitle = 'online'; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
appSidebarRight.profileElements.subtitle.innerText = subtitle; |
|
|
|
appSidebarRight.profileElements.subtitle.innerText = subtitle; |
|
|
@ -937,6 +1016,7 @@ export class AppImManager { |
|
|
|
} |
|
|
|
} |
|
|
|
this.bubbles = {}; |
|
|
|
this.bubbles = {}; |
|
|
|
this.dateMessages = {}; |
|
|
|
this.dateMessages = {}; |
|
|
|
|
|
|
|
this.bubbleGroups.cleanup(); |
|
|
|
this.unreaded = []; |
|
|
|
this.unreaded = []; |
|
|
|
this.unreadOut = []; |
|
|
|
this.unreadOut = []; |
|
|
|
this.loadMediaQueue = []; |
|
|
|
this.loadMediaQueue = []; |
|
|
@ -984,7 +1064,8 @@ export class AppImManager { |
|
|
|
if(dialog && lastMsgID == dialog.top_message) { |
|
|
|
if(dialog && lastMsgID == dialog.top_message) { |
|
|
|
this.scroll.scrollTop = this.scroll.scrollHeight; |
|
|
|
this.scroll.scrollTop = this.scroll.scrollHeight; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
this.bubbles[lastMsgID].scrollIntoView(); |
|
|
|
//this.bubbles[lastMsgID].scrollIntoView();
|
|
|
|
|
|
|
|
this.scrollable.scrollIntoView(this.bubbles[lastMsgID]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return Promise.resolve(true); |
|
|
|
return Promise.resolve(true); |
|
|
@ -1038,7 +1119,7 @@ export class AppImManager { |
|
|
|
this.titleEl.innerHTML = appSidebarRight.profileElements.name.innerHTML = title; |
|
|
|
this.titleEl.innerHTML = appSidebarRight.profileElements.name.innerHTML = title; |
|
|
|
|
|
|
|
|
|
|
|
this.topbar.style.display = this.goDownBtn.style.display = ''; |
|
|
|
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' : ''; |
|
|
|
this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : ''; |
|
|
|
|
|
|
|
|
|
|
@ -1048,6 +1129,8 @@ export class AppImManager { |
|
|
|
this.chatInner.classList.remove('is-chat'); |
|
|
|
this.chatInner.classList.remove('is-chat'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//this.scroll.scrollTop = this.scroll.scrollHeight;
|
|
|
|
|
|
|
|
|
|
|
|
return this.setPeerPromise = Promise.all([ |
|
|
|
return this.setPeerPromise = Promise.all([ |
|
|
|
this.getHistory(forwarding ? lastMsgID + 1 : lastMsgID).then(() => { |
|
|
|
this.getHistory(forwarding ? lastMsgID + 1 : lastMsgID).then(() => { |
|
|
|
////this.log('setPeer removing preloader');
|
|
|
|
////this.log('setPeer removing preloader');
|
|
|
@ -1068,18 +1151,18 @@ export class AppImManager { |
|
|
|
this.scroll.scrollTop = this.scroll.scrollHeight; |
|
|
|
this.scroll.scrollTop = this.scroll.scrollHeight; |
|
|
|
} |
|
|
|
} |
|
|
|
} else if(dialog && dialog.top_message) { // add last message, bc in getHistory will load < max_id
|
|
|
|
} 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.onScroll(); |
|
|
|
this.scrollable.onScroll(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.preloader.detach(); |
|
|
|
this.preloader.detach(); |
|
|
|
|
|
|
|
|
|
|
|
//setTimeout(() => {
|
|
|
|
//setTimeout(() => {
|
|
|
|
//appSidebarRight.fillProfileElements();
|
|
|
|
//appSidebarRight.fillProfileElements();
|
|
|
|
appSidebarRight.loadSidebarMedia(); |
|
|
|
appSidebarRight.loadSidebarMedia(true); |
|
|
|
//}, 500);
|
|
|
|
//}, 500);
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
@ -1123,7 +1206,6 @@ export class AppImManager { |
|
|
|
|
|
|
|
|
|
|
|
///////this.log('updateUnreadByDialog', maxID, dialog, this.unreadOut);
|
|
|
|
///////this.log('updateUnreadByDialog', maxID, dialog, this.unreadOut);
|
|
|
|
|
|
|
|
|
|
|
|
let length = this.unreadOut.length; |
|
|
|
|
|
|
|
this.unreadOut.forEachReverse((msgID, idx) => { |
|
|
|
this.unreadOut.forEachReverse((msgID, idx) => { |
|
|
|
if(msgID > 0 && msgID <= maxID) { |
|
|
|
if(msgID > 0 && msgID <= maxID) { |
|
|
|
let bubble = this.bubbles[msgID]; |
|
|
|
let bubble = this.bubbles[msgID]; |
|
|
@ -1148,13 +1230,9 @@ export class AppImManager { |
|
|
|
if(!(id in this.bubbles)) return; |
|
|
|
if(!(id in this.bubbles)) return; |
|
|
|
|
|
|
|
|
|
|
|
let bubble = this.bubbles[id]; |
|
|
|
let bubble = this.bubbles[id]; |
|
|
|
let parent = bubble.parentNode as HTMLDivElement; |
|
|
|
|
|
|
|
delete this.bubbles[id]; |
|
|
|
delete this.bubbles[id]; |
|
|
|
bubble.remove(); |
|
|
|
this.scrollable.removeElement(bubble); |
|
|
|
|
|
|
|
//bubble.remove();
|
|
|
|
if(!parent.childNodes.length) { |
|
|
|
|
|
|
|
parent.remove(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
lottieLoader.checkAnimations(); |
|
|
|
lottieLoader.checkAnimations(); |
|
|
@ -1210,11 +1288,36 @@ export class AppImManager { |
|
|
|
//bubble.innerHTML = '';
|
|
|
|
//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
|
|
|
|
// time section
|
|
|
|
|
|
|
|
|
|
|
|
let date = new Date(message.date * 1000); |
|
|
|
let date = new Date(message.date * 1000); |
|
|
|
let time = ('0' + date.getHours()).slice(-2) + |
|
|
|
let time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2); |
|
|
|
':' + ('0' + date.getMinutes()).slice(-2); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(message.views) { |
|
|
|
if(message.views) { |
|
|
|
bubble.classList.add('channel-post'); |
|
|
|
bubble.classList.add('channel-post'); |
|
|
@ -1382,8 +1485,8 @@ export class AppImManager { |
|
|
|
|
|
|
|
|
|
|
|
if(doc.type == 'gif' || doc.type == 'video') { |
|
|
|
if(doc.type == 'gif' || doc.type == 'video') { |
|
|
|
//if(doc.size <= 20e6) {
|
|
|
|
//if(doc.size <= 20e6) {
|
|
|
|
bubble.classList.add('video'); |
|
|
|
bubble.classList.add('video'); |
|
|
|
wrapVideo.call(this, doc, preview, message); |
|
|
|
wrapVideo.call(this, doc, preview, message); |
|
|
|
//}
|
|
|
|
//}
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
doc = null; |
|
|
|
doc = null; |
|
|
@ -1461,7 +1564,7 @@ export class AppImManager { |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
} else if(doc.mime_type == 'video/mp4' && doc.size <= 20e6) { |
|
|
|
} 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') { |
|
|
|
if(doc.type == 'round') { |
|
|
|
bubble.classList.add('round'); |
|
|
|
bubble.classList.add('round'); |
|
|
@ -1470,6 +1573,16 @@ export class AppImManager { |
|
|
|
bubble.classList.add('video'); |
|
|
|
bubble.classList.add('video'); |
|
|
|
wrapVideo.call(this, doc, attachmentDiv, message, true, null, false, doc.type == 'round'); |
|
|
|
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; |
|
|
|
break; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
let docDiv = wrapDocument(doc); |
|
|
|
let docDiv = wrapDocument(doc); |
|
|
@ -1483,11 +1596,11 @@ export class AppImManager { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
default: |
|
|
|
default: |
|
|
|
messageDiv.classList.remove('message-empty'); |
|
|
|
messageDiv.classList.remove('message-empty'); |
|
|
|
messageDiv.innerHTML = 'unrecognized media type: ' + message.media._; |
|
|
|
messageDiv.innerHTML = 'unrecognized media type: ' + message.media._; |
|
|
|
messageDiv.append(timeSpan); |
|
|
|
messageDiv.append(timeSpan); |
|
|
|
this.log.warn('unrecognized media type:', message.media._, message); |
|
|
|
this.log.warn('unrecognized media type:', message.media._, message); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(!processingWebPage) { |
|
|
|
if(!processingWebPage) { |
|
|
@ -1513,13 +1626,8 @@ export class AppImManager { |
|
|
|
if(message.savedFrom) { |
|
|
|
if(message.savedFrom) { |
|
|
|
let fwd = document.createElement('div'); |
|
|
|
let fwd = document.createElement('div'); |
|
|
|
fwd.classList.add('forward'/* , 'tgico-forward' */); |
|
|
|
fwd.classList.add('forward'/* , 'tgico-forward' */); |
|
|
|
fwd.innerHTML = ` |
|
|
|
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">
|
|
|
|
<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>`;
|
|
|
|
<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); |
|
|
|
bubbleContainer.append(fwd); |
|
|
|
bubble.dataset.savedFrom = message.savedFrom; |
|
|
|
bubble.dataset.savedFrom = message.savedFrom; |
|
|
|
} |
|
|
|
} |
|
|
@ -1568,17 +1676,9 @@ export class AppImManager { |
|
|
|
} else /* if(!message.reply_to_mid) */ { |
|
|
|
} else /* if(!message.reply_to_mid) */ { |
|
|
|
bubble.classList.add('hide-name'); |
|
|
|
bubble.classList.add('hide-name'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//bubble.prepend(avatarDiv);
|
|
|
|
|
|
|
|
/* if(messageDiv.nextElementSibling) { |
|
|
|
|
|
|
|
bubble.insertBefore(avatarDiv, messageDiv.nextElementSibling); |
|
|
|
|
|
|
|
} else { */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(!our && this.peerID < 0 && |
|
|
|
if(!our && this.peerID < 0 && (!appPeersManager.isChannel(this.peerID) || appPeersManager.isMegagroup(this.peerID))) { |
|
|
|
(!appPeersManager.isChannel(this.peerID) || appPeersManager.isMegagroup(this.peerID))) { |
|
|
|
|
|
|
|
let avatarDiv = document.createElement('div'); |
|
|
|
let avatarDiv = document.createElement('div'); |
|
|
|
avatarDiv.classList.add('user-avatar'); |
|
|
|
avatarDiv.classList.add('user-avatar'); |
|
|
|
|
|
|
|
|
|
|
@ -1599,26 +1699,6 @@ export class AppImManager { |
|
|
|
bubble.classList.add('hide-name'); |
|
|
|
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'); |
|
|
|
bubble.classList.add(our ? 'is-out' : 'is-in'); |
|
|
|
if(updatePosition) { |
|
|
|
if(updatePosition) { |
|
|
|
if(reverse) { |
|
|
|
if(reverse) { |
|
|
@ -1627,6 +1707,8 @@ export class AppImManager { |
|
|
|
this.scrollable.append(bubble); |
|
|
|
this.scrollable.append(bubble); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.bubbleGroups.addBubble(bubble, message, reverse); |
|
|
|
|
|
|
|
|
|
|
|
let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); |
|
|
|
let justDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); |
|
|
|
let dateTimestamp = justDate.getTime(); |
|
|
|
let dateTimestamp = justDate.getTime(); |
|
|
|
if(!(dateTimestamp in this.dateMessages)) { |
|
|
|
if(!(dateTimestamp in this.dateMessages)) { |
|
|
@ -1640,11 +1722,10 @@ export class AppImManager { |
|
|
|
if(today < date) { |
|
|
|
if(today < date) { |
|
|
|
str = 'Today'; |
|
|
|
str = 'Today'; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
const months = ['January', 'February', 'March', 'April', 'May', 'June', |
|
|
|
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; |
|
|
|
'July', 'August', 'September', 'October', 'November', 'December']; |
|
|
|
|
|
|
|
str = justDate.getFullYear() == new Date().getFullYear() ? |
|
|
|
str = justDate.getFullYear() == new Date().getFullYear() ? |
|
|
|
months[justDate.getMonth()] + ' ' + justDate.getDate() : |
|
|
|
months[justDate.getMonth()] + ' ' + justDate.getDate() : |
|
|
|
justDate.toISOString().split('T')[0].split('-').reverse().join('.'); |
|
|
|
justDate.toISOString().split('T')[0].split('-').reverse().join('.'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let div = document.createElement('div'); |
|
|
|
let div = document.createElement('div'); |
|
|
@ -1664,6 +1745,8 @@ export class AppImManager { |
|
|
|
this.scrollable.insertBefore(dateMessage.div, bubble); |
|
|
|
this.scrollable.insertBefore(dateMessage.div, bubble); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
this.bubbleGroups.updateGroupByMessageID(message.mid); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* if(bubble.classList.contains('webpage')) { |
|
|
|
/* if(bubble.classList.contains('webpage')) { |
|
|
@ -1675,8 +1758,6 @@ export class AppImManager { |
|
|
|
if(!multipleRender) { |
|
|
|
if(!multipleRender) { |
|
|
|
this.scrollPosition.restore(); // лагает из-за этого
|
|
|
|
this.scrollPosition.restore(); // лагает из-за этого
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//this.log('history msg', message);
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// reverse means scroll up
|
|
|
|
// reverse means scroll up
|
|
|
@ -1688,9 +1769,7 @@ export class AppImManager { |
|
|
|
maxID = dialog.top_message/* + 1 */; |
|
|
|
maxID = dialog.top_message/* + 1 */; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let loadCount = Object.keys(this.bubbles).length > 0 ? |
|
|
|
let loadCount = Object.keys(this.bubbles).length > 0 ? 20 : this.scrollable.container.parentElement.scrollHeight / 30 * 1.25 | 0; |
|
|
|
20 : |
|
|
|
|
|
|
|
this.scrollable.container.parentElement.scrollHeight / 30 * 1.25 | 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* if(testScroll) { |
|
|
|
/* if(testScroll) { |
|
|
|
loadCount = 1; |
|
|
|
loadCount = 1; |
|
|
@ -1800,7 +1879,7 @@ export class AppImManager { |
|
|
|
peer: inputPeer |
|
|
|
peer: inputPeer |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let settings: any = { |
|
|
|
let settings = { |
|
|
|
_: 'inputPeerNotifySettings', |
|
|
|
_: 'inputPeerNotifySettings', |
|
|
|
flags: 0, |
|
|
|
flags: 0, |
|
|
|
mute_until: 0 |
|
|
|
mute_until: 0 |
|
|
@ -1842,49 +1921,47 @@ export class AppImManager { |
|
|
|
switch(update._) { |
|
|
|
switch(update._) { |
|
|
|
case 'updateUserTyping': |
|
|
|
case 'updateUserTyping': |
|
|
|
case 'updateChatUserTyping': |
|
|
|
case 'updateChatUserTyping': |
|
|
|
if(this.myID == update.user_id) { |
|
|
|
if(this.myID == update.user_id) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var peerID = update._ == 'updateUserTyping' ? update.user_id : -update.chat_id; |
|
|
|
|
|
|
|
this.typingUsers[update.user_id] = peerID; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(!appUsersManager.hasUser(update.user_id)) { |
|
|
|
var peerID = update._ == 'updateUserTyping' ? update.user_id : -update.chat_id; |
|
|
|
if(update.chat_id && |
|
|
|
this.typingUsers[update.user_id] = peerID; |
|
|
|
appChatsManager.hasChat(update.chat_id) && |
|
|
|
|
|
|
|
!appChatsManager.isChannel(update.chat_id)) { |
|
|
|
|
|
|
|
appProfileManager.getChatFull(update.chat_id); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//return;
|
|
|
|
if(!appUsersManager.hasUser(update.user_id)) { |
|
|
|
|
|
|
|
if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) { |
|
|
|
|
|
|
|
appProfileManager.getChatFull(update.chat_id); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
appUsersManager.forceUserOnline(update.user_id); |
|
|
|
//return;
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0]; |
|
|
|
appUsersManager.forceUserOnline(update.user_id); |
|
|
|
let currentPeer = this.peerID == peerID; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(this.typingTimeouts[peerID]) clearTimeout(this.typingTimeouts[peerID]); |
|
|
|
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0]; |
|
|
|
else if(dialog) { |
|
|
|
let currentPeer = this.peerID == peerID; |
|
|
|
appDialogsManager.setTyping(dialog, appUsersManager.getUser(update.user_id)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(currentPeer) { // user
|
|
|
|
if(this.typingTimeouts[peerID]) clearTimeout(this.typingTimeouts[peerID]); |
|
|
|
this.setPeerStatus(); |
|
|
|
else if(dialog) { |
|
|
|
} |
|
|
|
appDialogsManager.setTyping(dialog, appUsersManager.getUser(update.user_id)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(currentPeer) { // user
|
|
|
|
|
|
|
|
this.setPeerStatus(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.typingTimeouts[peerID] = setTimeout(() => { |
|
|
|
this.typingTimeouts[peerID] = setTimeout(() => { |
|
|
|
this.typingTimeouts[peerID] = 0; |
|
|
|
this.typingTimeouts[peerID] = 0; |
|
|
|
delete this.typingUsers[update.user_id]; |
|
|
|
delete this.typingUsers[update.user_id]; |
|
|
|
|
|
|
|
|
|
|
|
if(dialog) { |
|
|
|
if(dialog) { |
|
|
|
appDialogsManager.unsetTyping(dialog); |
|
|
|
appDialogsManager.unsetTyping(dialog); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// лень просчитывать случаи
|
|
|
|
// лень просчитывать случаи
|
|
|
|
this.setPeerStatus(); |
|
|
|
this.setPeerStatus(); |
|
|
|
}, 6000); |
|
|
|
}, 6000); |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case 'updateNotifySettings': { |
|
|
|
case 'updateNotifySettings': { |
|
|
|
let {peer, notify_settings} = update; |
|
|
|
let {peer, notify_settings} = update; |
|
|
|