Browse Source

Chat and sidebar load onload & media viewer supports aspects & reply markup buttons (only single answer)

master
morethanwords 4 years ago
parent
commit
fee0aab1d7
  1. 9
      src/components/appSelectPeers.ts
  2. 10
      src/components/bubbleGroups.ts
  3. 2
      src/components/lazyLoadQueue.ts
  4. 23
      src/components/misc.ts
  5. 57
      src/components/scrollable_new.ts
  6. 95
      src/components/wrappers.ts
  7. 421
      src/lib/appManagers/AppInlineBotsManager.ts
  8. 52
      src/lib/appManagers/apiUpdatesManager.ts
  9. 2
      src/lib/appManagers/appChatsManager.ts
  10. 68
      src/lib/appManagers/appDialogsManager.ts
  11. 750
      src/lib/appManagers/appImManager.ts
  12. 173
      src/lib/appManagers/appMediaViewer.ts
  13. 389
      src/lib/appManagers/appMessagesManager.ts
  14. 29
      src/lib/appManagers/appPhotosManager.ts
  15. 231
      src/lib/appManagers/appSidebarRight.ts
  16. 10
      src/lib/appManagers/appStickersManager.ts
  17. 2
      src/lib/appManagers/appUsersManager.ts
  18. 7
      src/lib/polyfill.ts
  19. 7
      src/lib/storage.ts
  20. 5
      src/lib/utils.js
  21. 107
      src/scss/partials/_chatBubble.scss
  22. 2
      src/scss/partials/_fonts.scss
  23. 1
      src/scss/partials/_ico.scss
  24. 67
      src/scss/partials/_mediaViewer.scss
  25. 19
      src/scss/partials/_rightSIdebar.scss
  26. 4
      src/scss/partials/_selector.scss
  27. 31
      src/scss/style.scss
  28. 1
      webpack.common.js

9
src/components/appSelectPeers.ts

@ -5,7 +5,6 @@ import appDialogsManager from "../lib/appManagers/appDialogsManager";
import appChatsManager from "../lib/appManagers/appChatsManager"; import appChatsManager from "../lib/appManagers/appChatsManager";
import appUsersManager from "../lib/appManagers/appUsersManager"; import appUsersManager from "../lib/appManagers/appUsersManager";
import { appPeersManager } from "../lib/services"; import { appPeersManager } from "../lib/services";
import appProfileManager from "../lib/appManagers/appProfileManager";
import appPhotosManager from "../lib/appManagers/appPhotosManager"; import appPhotosManager from "../lib/appManagers/appPhotosManager";
export class AppSelectPeers { export class AppSelectPeers {
@ -116,16 +115,18 @@ export class AppSelectPeers {
appMessagesManager.getConversations(this.offsetIndex, 50, 0).then(value => { appMessagesManager.getConversations(this.offsetIndex, 50, 0).then(value => {
let dialogs = value.dialogs; let dialogs = value.dialogs;
this.offsetIndex = dialogs[value.dialogs.length - 1].index || 0; let newOffsetIndex = dialogs[value.dialogs.length - 1].index || 0;
if(dialogs[0].peerID != this.myID) { dialogs = dialogs.filter(d => d.peerID != this.myID);
dialogs.findAndSplice(d => d.peerID == this.myID); if(!this.offsetIndex) {
dialogs.unshift({ dialogs.unshift({
peerID: this.myID, peerID: this.myID,
pFlags: {} pFlags: {}
} as any); } as any);
} }
this.offsetIndex = newOffsetIndex;
this.renderResults(dialogs.map(dialog => dialog.peerID)); this.renderResults(dialogs.map(dialog => dialog.peerID));
}); });
} }

10
src/components/bubbleGroups.ts

@ -12,6 +12,8 @@ export default class BubbleGroups {
details.group.findAndSplice(d => d == bubble); details.group.findAndSplice(d => d == bubble);
if(!details.group.length) { if(!details.group.length) {
this.groups.findAndSplice(g => g == details.group); this.groups.findAndSplice(g => g == details.group);
} else {
this.updateGroup(details.group);
} }
} }
} }
@ -49,7 +51,7 @@ export default class BubbleGroups {
//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.bubblesByGroups[reverse ? 'unshift' : 'push']({timestamp, fromID, mid: message.mid, group});
this.updateGroup(group, reverse); this.updateGroup(group);
} }
setClipIfNeeded(bubble: HTMLDivElement, remove = false) { setClipIfNeeded(bubble: HTMLDivElement, remove = false) {
@ -100,7 +102,7 @@ export default class BubbleGroups {
} }
} }
updateGroup(group: HTMLDivElement[], reverse = false) { updateGroup(group: HTMLDivElement[]) {
/* if(this.updateRAFs.has(group)) { /* if(this.updateRAFs.has(group)) {
window.cancelAnimationFrame(this.updateRAFs.get(group)); window.cancelAnimationFrame(this.updateRAFs.get(group));
this.updateRAFs.delete(group); this.updateRAFs.delete(group);
@ -115,8 +117,6 @@ export default class BubbleGroups {
let first = group[0]; let first = group[0];
//appImManager.scrollPosition.prepareFor(reverse ? 'up' : 'down');
//console.log('updateGroup', group, first); //console.log('updateGroup', group, first);
if(group.length == 1) { if(group.length == 1) {
@ -140,8 +140,6 @@ export default class BubbleGroups {
last.classList.remove('is-group-first'); last.classList.remove('is-group-first');
last.classList.add('is-group-last'); last.classList.add('is-group-last');
this.setClipIfNeeded(last); this.setClipIfNeeded(last);
//appImManager.scrollPosition.restore();
//})); //}));
} }

2
src/components/lazyLoadQueue.ts

@ -73,7 +73,7 @@ export default class LazyLoadQueue {
this.debug && this.log('will load media', this.lockPromise, item); this.debug && this.log('will load media', this.lockPromise, item);
try { try {
if(this.lockPromise) { if(this.lockPromise && false) {
let perf = performance.now(); let perf = performance.now();
await this.lockPromise; await this.lockPromise;

23
src/components/misc.ts

@ -3,6 +3,8 @@ import Config from "../lib/config";
let rippleClickID = 0; let rippleClickID = 0;
export function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null) { export function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null) {
if(elem.querySelector('.c-ripple')) return;
let r = document.createElement('div'); let r = document.createElement('div');
r.classList.add('c-ripple'); r.classList.add('c-ripple');
@ -99,6 +101,19 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool
}); });
} }
const toastEl = document.createElement('div');
toastEl.classList.add('toast');
export function toast(html: string) {
toastEl.innerHTML = html;
document.body.append(toastEl);
if(toastEl.dataset.timeout) clearTimeout(+toastEl.dataset.timeout);
toastEl.dataset.timeout = '' + setTimeout(() => {
toastEl.remove();
delete toastEl.dataset.timeout;
}, 3000);
}
let loadedURLs: {[url: string]: boolean} = {}; let loadedURLs: {[url: string]: boolean} = {};
let set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string) => { let set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string) => {
if(elem instanceof HTMLImageElement || elem instanceof HTMLSourceElement) elem.src = url; if(elem instanceof HTMLImageElement || elem instanceof HTMLSourceElement) elem.src = url;
@ -117,10 +132,12 @@ export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGIma
} else { } else {
let loader = new Image(); let loader = new Image();
loader.src = url; loader.src = url;
loader.onload = () => { //let perf = performance.now();
loader.addEventListener('load', () => {
set(elem, url); set(elem, url);
loadedURLs[url] = true; loadedURLs[url] = true;
}; //console.log('onload:', url, performance.now() - perf);
});
} }
return false; return false;
@ -336,7 +353,7 @@ let onMouseMove = (e: MouseEvent) => {
}; };
let onClick = (e: MouseEvent) => { let onClick = (e: MouseEvent) => {
e.preventDefault(); //e.preventDefault();
closeBtnMenu(); closeBtnMenu();
}; };

57
src/components/scrollable_new.ts

@ -367,48 +367,39 @@ export default class Scrollable {
return !!element.parentElement; return !!element.parentElement;
} }
public scrollIntoView(element: HTMLElement, smooth = true, fromUp = false) { public scrollIntoView(element: HTMLElement, smooth = true) {
if(element.parentElement && !this.scrollLocked) { if(element.parentElement && !this.scrollLocked) {
let scrollTop = this.scrollTop; let isFirstUnread = element.classList.contains('is-first-unread');
let offsetTop = element.offsetTop; let offsetTop = element.offsetTop;
let clientHeight = this.container.clientHeight; if(!smooth && isFirstUnread) {
this.scrollTo(offsetTop, false);
return;
}
let clientHeight = this.container.clientHeight;
let height = element.scrollHeight; let height = element.scrollHeight;
let diff = (clientHeight - height) / 2; offsetTop -= (clientHeight - height) / 2;
this.scrollTo(offsetTop, smooth);
}
}
/* if(scrollTop < offsetTop) { public scrollTo(top: number, smooth = true) {
offsetTop += diff; if(this.scrollLocked) return;
} else { */
offsetTop -= diff;
//}
if(element.dataset.timeout) { let scrollTop = this.scrollTop;
clearTimeout(+element.dataset.timeout); if(scrollTop == Math.floor(top)) {
element.classList.remove('is-selected'); return;
void element.offsetWidth; // reflow }
}
element.classList.add('is-selected');
element.dataset.timeout = '' + setTimeout(() => {
element.classList.remove('is-selected');
delete element.dataset.timeout;
}, 2000);
if(scrollTop == Math.floor(offsetTop)) { if(this.scrollLocked) clearTimeout(this.scrollLocked);
return; this.scrollLocked = setTimeout(() => {
} this.scrollLocked = 0;
this.onScroll();
}, 468);
if(this.scrollLocked) clearTimeout(this.scrollLocked); this.container.scrollTo({behavior: smooth ? 'smooth' : 'auto', top});
this.scrollLocked = setTimeout(() => {
this.scrollLocked = 0;
this.onScroll();
}, 468);
if(fromUp) {
this.container.scrollTo({behavior: 'auto', top: 0});
}
this.container.scrollTo({behavior: smooth ? 'smooth' : 'auto', top: offsetTop});
//element.scrollIntoView({behavior: 'smooth', block: 'center'});
}
} }
public removeElement(element: Element) { public removeElement(element: Element) {

95
src/components/wrappers.ts

@ -15,7 +15,6 @@ import { CancellablePromise } from '../lib/polyfill';
import { renderImageFromUrl } from './misc'; import { renderImageFromUrl } from './misc';
import appMessagesManager from '../lib/appManagers/appMessagesManager'; import appMessagesManager from '../lib/appManagers/appMessagesManager';
import { Layouter, RectPart } from './groupedLayout'; import { Layouter, RectPart } from './groupedLayout';
import { Poll, PollResults } from '../lib/appManagers/appPollsManager';
import PollElement from './poll'; import PollElement from './poll';
export type MTDocument = { export type MTDocument = {
@ -135,47 +134,43 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
} }
} }
let loadVideo = () => { let loadVideo = async() => {
let promise = appDocsManager.downloadDoc(doc);
if(message.media.preloader) { // means upload if(message.media.preloader) { // means upload
message.media.preloader.attach(container); message.media.preloader.attach(container);
} else if(!doc.downloaded) { } else if(!doc.downloaded) {
let preloader = new ProgressivePreloader(container, true); let preloader = new ProgressivePreloader(container, true);
let promise = appDocsManager.downloadDoc(doc);
preloader.attach(container, true, promise); preloader.attach(container, true, promise);
await promise;
} }
return promise.then(blob => {
if(middleware && !middleware()) {
return;
}
//return; if(middleware && !middleware()) {
return;
//console.log('loaded doc:', doc, doc.url, blob, container); }
renderImageFromUrl(source, doc.url);
source.type = doc.mime_type;
video.append(source);
if(!withTail) { console.log('loaded doc:', doc, doc.url, container);
if(img && container.contains(img)) {
container.removeChild(img); renderImageFromUrl(source, doc.url);
} source.type = doc.mime_type;
video.append(source);
container.append(video); if(!withTail) {
} if(img && container.contains(img)) {
container.removeChild(img);
if(doc.type == 'gif') {
video.autoplay = true;
video.loop = true;
} else if(doc.type == 'round') {
//video.dataset.ckin = doc.type == 'round' ? 'circle' : 'default';
video.dataset.ckin = 'circle';
video.dataset.overlay = '1';
let player = new VideoPlayer(video/* , doc.type != 'round' */);
} }
});
container.append(video);
}
if(doc.type == 'gif') {
video.autoplay = true;
video.loop = true;
} else if(doc.type == 'round') {
//video.dataset.ckin = doc.type == 'round' ? 'circle' : 'default';
video.dataset.ckin = 'circle';
video.dataset.overlay = '1';
let player = new VideoPlayer(video/* , doc.type != 'round' */);
}
}; };
if(doc.size >= 20e6 && !doc.downloaded) { if(doc.size >= 20e6 && !doc.downloaded) {
@ -826,11 +821,11 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
if(!downloaded && (!div.firstElementChild || div.firstElementChild.tagName != 'IMG')) { if(!downloaded && (!div.firstElementChild || div.firstElementChild.tagName != 'IMG')) {
img.style.opacity = '' + 0; img.style.opacity = '' + 0;
img.onload = () => { img.addEventListener('load', () => {
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
img.style.opacity = ''; img.style.opacity = '';
}); });
}; });
} }
if(!doc.url) { if(!doc.url) {
@ -889,8 +884,8 @@ export function wrapReply(title: string, subtitle: string, message?: any) {
} }
appPhotosManager.preloadPhoto(photo, appPhotosManager.choosePhotoSize(photo, 32, 32)) appPhotosManager.preloadPhoto(photo, appPhotosManager.choosePhotoSize(photo, 32, 32))
.then(blob => { .then(() => {
renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : URL.createObjectURL(blob)); renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : appPhotosManager.getDocumentCachedThumb(photo.id).url);
}); });
replyContent.append(replyMedia); replyContent.append(replyMedia);
@ -1004,34 +999,6 @@ export function wrapAlbum({groupID, attachmentDiv, middleware, uploading, lazyLo
}); });
} }
/* let load = () => appPhotosManager.preloadPhoto(media._ == 'photo' ? media.id : media, size)
.then((blob) => {
if(middleware && !middleware()) {
console.warn('peer changed');
return;
}
if(!uploading) {
preloader.detach();
}
if(media && media.url) {
renderImageFromUrl(div, media.url);
} else {
let url = URL.createObjectURL(blob);
let img = new Image();
img.src = url;
img.onload = () => {
div.style.backgroundImage = 'url(' + url + ')';
};
}
//div.style.backgroundImage = 'url(' + url + ')';
});
load(); */
// @ts-ignore // @ts-ignore
//div.style.backgroundColor = '#' + Math.floor(Math.random() * (2 ** 24 - 1)).toString(16).padStart(6, '0'); //div.style.backgroundColor = '#' + Math.floor(Math.random() * (2 ** 24 - 1)).toString(16).padStart(6, '0');

421
src/lib/appManagers/AppInlineBotsManager.ts

@ -0,0 +1,421 @@
import appMessagesManager from "./appMessagesManager";
import apiManagerProxy from "../mtproto/mtprotoworker";
import { appPeersManager } from "../services";
import appMessagesIDsManager from "./appMessagesIDsManager";
import { toast } from "../../components/misc";
import { RichTextProcessor } from "../richtextprocessor";
export class AppInlineBotsManager {
/* private inlineResults: any = {};
function getPopularBots () {
return Storage.get('inline_bots_popular').then(function (bots) {
var result = []
var i, len
var userID
if (bots && bots.length) {
var now = tsNow(true)
for (i = 0, len = bots.length; i < len; i++) {
if ((now - bots[i][3]) > 14 * 86400) {
continue
}
userID = bots[i][0]
if (!AppUsersManager.hasUser(userID)) {
AppUsersManager.saveApiUser(bots[i][1])
}
result.push({id: userID, rate: bots[i][2], date: bots[i][3]})
}
}
return result
})
}
function pushPopularBot (id) {
getPopularBots().then(function (bots) {
var exists = false
var count = bots.length
var result = []
for (var i = 0; i < count; i++) {
if (bots[i].id == id) {
exists = true
bots[i].rate++
bots[i].date = tsNow(true)
}
var user = AppUsersManager.getUser(bots[i].id)
result.push([bots[i].id, user, bots[i].rate, bots[i].date])
}
if (exists) {
result.sort(function (a, b) {
return b[2] - a[2]
})
} else {
if (result.length > 15) {
result = result.slice(0, 15)
}
result.push([id, AppUsersManager.getUser(id), 1, tsNow(true)])
}
ConfigStorage.set({inline_bots_popular: result})
$rootScope.$broadcast('inline_bots_popular')
})
}
function resolveInlineMention (username) {
return AppPeersManager.resolveUsername(username).then(function (peerID) {
if (peerID > 0) {
var bot = AppUsersManager.getUser(peerID)
if (bot.pFlags.bot && bot.bot_inline_placeholder !== undefined) {
var resolvedBot = {
username: username,
id: peerID,
placeholder: bot.bot_inline_placeholder
}
if (bot.pFlags.bot_inline_geo &&
GeoLocationManager.isAvailable()) {
return checkGeoLocationAccess(peerID).then(function () {
return GeoLocationManager.getPosition().then(function (coords) {
resolvedBot.geo = coords
return qSync.when(resolvedBot)
})
})['catch'](function () {
return qSync.when(resolvedBot)
})
}
return qSync.when(resolvedBot)
}
}
return $q.reject()
}, function (error) {
error.handled = true
return $q.reject(error)
})
}
function getInlineResults (peerID, botID, query, geo, offset) {
return MtpApiManager.invokeApi('messages.getInlineBotResults', {
flags: 0 | (geo ? 1 : 0),
bot: AppUsersManager.getUserInput(botID),
peer: AppPeersManager.getInputPeerByID(peerID),
query: query,
geo_point: geo && {_: 'inputGeoPoint', lat: geo['lat'], long: geo['long']},
offset: offset
}, {timeout: 1, stopTime: -1, noErrorBox: true}).then(function (botResults) {
var queryID = botResults.query_id
delete botResults._
delete botResults.flags
delete botResults.query_id
if (botResults.switch_pm) {
botResults.switch_pm.rText = RichTextProcessor.wrapRichText(botResults.switch_pm.text, {noLinebreaks: true, noLinks: true})
}
angular.forEach(botResults.results, function (result) {
var qID = queryID + '_' + result.id
result.qID = qID
result.botID = botID
result.rTitle = RichTextProcessor.wrapRichText(result.title, {noLinebreaks: true, noLinks: true})
result.rDescription = RichTextProcessor.wrapRichText(result.description, {noLinebreaks: true, noLinks: true})
result.initials = (result.url || result.title || result.type || '').substr(0, 1)
if (result.document) {
AppDocsManager.saveDoc(result.document)
}
if (result.photo) {
AppPhotosManager.savePhoto(result.photo)
}
inlineResults[qID] = result
})
return botResults
})
}
function regroupWrappedResults (results, rowW, rowH) {
if (!results ||
!results[0] ||
['photo', 'gif', 'sticker'].indexOf(results[0].type) == -1) {
return
}
var ratios = []
angular.forEach(results, function (result) {
var w
var h, doc
var photo
if (result._ == 'botInlineMediaResult') {
if (doc = result.document) {
w = result.document.w
h = result.document.h
}
else if (photo = result.photo) {
var photoSize = (photo.sizes || [])[0]
w = photoSize && photoSize.w
h = photoSize && photoSize.h
}
}else {
w = result.w
h = result.h
}
if (!w || !h) {
w = h = 1
}
ratios.push(w / h)
})
var rows = []
var curCnt = 0
var curW = 0
angular.forEach(ratios, function (ratio) {
var w = ratio * rowH
curW += w
if (!curCnt || curCnt < 4 && curW < (rowW * 1.1)) {
curCnt++
} else {
rows.push(curCnt)
curCnt = 1
curW = w
}
})
if (curCnt) {
rows.push(curCnt)
}
var i = 0
var thumbs = []
var lastRowI = rows.length - 1
angular.forEach(rows, function (rowCnt, rowI) {
var lastRow = rowI == lastRowI
var curRatios = ratios.slice(i, i + rowCnt)
var sumRatios = 0
angular.forEach(curRatios, function (ratio) {
sumRatios += ratio
})
angular.forEach(curRatios, function (ratio, j) {
var thumbH = rowH
var thumbW = rowW * ratio / sumRatios
var realW = thumbH * ratio
if (lastRow && thumbW > realW) {
thumbW = realW
}
var result = results[i + j]
result.thumbW = Math.floor(thumbW) - 2
result.thumbH = Math.floor(thumbH) - 2
})
i += rowCnt
})
}
function switchToPM (fromPeerID, botID, startParam) {
var peerString = AppPeersManager.getPeerString(fromPeerID)
var setHash = {}
setHash['inline_switch_pm' + botID] = {peer: peerString, time: tsNow()}
Storage.set(setHash)
$rootScope.$broadcast('history_focus', {peerString: AppPeersManager.getPeerString(botID)})
AppMessagesManager.startBot(botID, 0, startParam)
}
function checkSwitchReturn (botID) {
var bot = AppUsersManager.getUser(botID)
if (!bot || !bot.pFlags.bot || !bot.bot_inline_placeholder) {
return qSync.when(false)
}
var key = 'inline_switch_pm' + botID
return Storage.get(key).then(function (peerData) {
if (peerData) {
Storage.remove(key)
if (tsNow() - peerData.time < 3600000) {
return peerData.peer
}
}
return false
})
}
function switchInlineQuery (botID, toPeerString, query) {
$rootScope.$broadcast('history_focus', {
peerString: toPeerString,
attachment: {
_: 'inline_query',
mention: '@' + AppUsersManager.getUser(botID).username,
query: query
}
})
}
function switchInlineButtonClick (id, button) {
var message = AppMessagesManager.getMessage(id)
var botID = message.viaBotID || message.fromID
if (button.pFlags && button.pFlags.same_peer) {
var peerID = AppMessagesManager.getMessagePeer(message)
var toPeerString = AppPeersManager.getPeerString(peerID)
switchInlineQuery(botID, toPeerString, button.query)
return
}
return checkSwitchReturn(botID).then(function (retPeerString) {
if (retPeerString) {
return switchInlineQuery(botID, retPeerString, button.query)
}
PeersSelectService.selectPeer({
canSend: true
}).then(function (toPeerString) {
return switchInlineQuery(botID, toPeerString, button.query)
})
})
} */
public callbackButtonClick(mid: number, button: any) {
let message = appMessagesManager.getMessage(mid);
let peerID = appMessagesManager.getMessagePeer(message);
return apiManagerProxy.invokeApi('messages.getBotCallbackAnswer', {
flags: 1,
peer: appPeersManager.getInputPeerByID(peerID),
msg_id: appMessagesIDsManager.getMessageLocalID(mid),
data: button.data
}, {timeout: 1, stopTime: -1, noErrorBox: true}).then((callbackAnswer: any) => {
if(typeof callbackAnswer.message === 'string' && callbackAnswer.message.length) {
toast(RichTextProcessor.wrapRichText(callbackAnswer.message, {noLinks: true, noLinebreaks: true}));
}
console.log('callbackButtonClick callbackAnswer:', callbackAnswer);
});
}
/* function gameButtonClick (id) {
var message = AppMessagesManager.getMessage(id)
var peerID = AppMessagesManager.getMessagePeer(message)
return MtpApiManager.invokeApi('messages.getBotCallbackAnswer', {
flags: 2,
peer: AppPeersManager.getInputPeerByID(peerID),
msg_id: AppMessagesIDsManager.getMessageLocalID(id)
}, {timeout: 1, stopTime: -1, noErrorBox: true}).then(function (callbackAnswer) {
if (typeof callbackAnswer.message === 'string' &&
callbackAnswer.message.length) {
showCallbackMessage(callbackAnswer.message, callbackAnswer.pFlags.alert)
}
else if (typeof callbackAnswer.url === 'string') {
AppGamesManager.openGame(message.media.game.id, id, callbackAnswer.url)
}
})
}
function sendInlineResult (peerID, qID, options) {
var inlineResult = inlineResults[qID]
if (inlineResult === undefined) {
return false
}
pushPopularBot(inlineResult.botID)
var splitted = qID.split('_')
var queryID = splitted.shift()
var resultID = splitted.join('_')
options = options || {}
options.viaBotID = inlineResult.botID
options.queryID = queryID
options.resultID = resultID
if (inlineResult.send_message.reply_markup) {
options.reply_markup = inlineResult.send_message.reply_markup
}
if (inlineResult.send_message._ == 'botInlineMessageText') {
options.entities = inlineResult.send_message.entities
AppMessagesManager.sendText(peerID, inlineResult.send_message.message, options)
} else {
var caption = ''
var inputMedia = false
switch (inlineResult.send_message._) {
case 'botInlineMessageMediaAuto':
caption = inlineResult.send_message.caption
if (inlineResult._ == 'botInlineMediaResult') {
var doc = inlineResult.document
var photo = inlineResult.photo
if (doc) {
inputMedia = {
_: 'inputMediaDocument',
id: {_: 'inputDocument', id: doc.id, access_hash: doc.access_hash},
caption: caption
}
} else {
inputMedia = {
_: 'inputMediaPhoto',
id: {_: 'inputPhoto', id: photo.id, access_hash: photo.access_hash},
caption: caption
}
}
}
break
case 'botInlineMessageMediaGeo':
inputMedia = {
_: 'inputMediaGeoPoint',
geo_point: {
_: 'inputGeoPoint',
'lat': inlineResult.send_message.geo['lat'],
'long': inlineResult.send_message.geo['long']
}
}
break
case 'botInlineMessageMediaVenue':
inputMedia = {
_: 'inputMediaVenue',
geo_point: {
_: 'inputGeoPoint',
'lat': inlineResult.send_message.geo['lat'],
'long': inlineResult.send_message.geo['long']
},
title: inlineResult.send_message.title,
address: inlineResult.send_message.address,
provider: inlineResult.send_message.provider,
venue_id: inlineResult.send_message.venue_id
}
break
case 'botInlineMessageMediaContact':
inputMedia = {
_: 'inputMediaContact',
phone_number: inlineResult.send_message.phone_number,
first_name: inlineResult.send_message.first_name,
last_name: inlineResult.send_message.last_name
}
break
}
if (!inputMedia) {
inputMedia = {
_: 'messageMediaPending',
type: inlineResult.type,
file_name: inlineResult.title || inlineResult.content_url || inlineResult.url,
size: 0,
progress: {percent: 30, total: 0}
}
}
AppMessagesManager.sendOther(peerID, inputMedia, options)
}
}
function checkGeoLocationAccess (botID) {
var key = 'bot_access_geo' + botID
return Storage.get(key).then(function (geoAccess) {
if (geoAccess && geoAccess.granted) {
return true
}
return ErrorService.confirm({
type: 'BOT_ACCESS_GEO_INLINE'
}).then(function () {
var setHash = {}
setHash[key] = {granted: true, time: tsNow()}
Storage.set(setHash)
return true
}, function () {
var setHash = {}
setHash[key] = {denied: true, time: tsNow()}
Storage.set(setHash)
return $q.reject()
})
})
} */
}
const appInlineBotsManager = new AppInlineBotsManager();
export default appInlineBotsManager;

52
src/lib/appManagers/apiUpdatesManager.ts

@ -13,9 +13,9 @@ export class ApiUpdatesManager {
syncPending: any, syncPending: any,
syncLoading: any, syncLoading: any,
seq?: any, seq?: number,
pts?: any, pts?: number,
date?: any date?: number
} = { } = {
pendingPtsUpdates: [], pendingPtsUpdates: [],
pendingSeqUpdates: {}, pendingSeqUpdates: {},
@ -24,14 +24,7 @@ export class ApiUpdatesManager {
}; };
public channelStates: any = {}; public channelStates: any = {};
public myID = 0;
private attached = false; private attached = false;
constructor() {
apiManager.getUserID().then((id) => {
this.myID = id;
});
}
public popPendingSeqUpdate() { public popPendingSeqUpdate() {
var nextSeq = this.updatesState.seq + 1; var nextSeq = this.updatesState.seq + 1;
@ -141,10 +134,10 @@ export class ApiUpdatesManager {
case 'updateShortMessage': case 'updateShortMessage':
case 'updateShortChatMessage': case 'updateShortChatMessage':
var isOut = updateMessage.flags & 2; var isOut = updateMessage.flags & 2;
var fromID = updateMessage.from_id || (isOut ? this.myID : updateMessage.user_id); var fromID = updateMessage.from_id || (isOut ? $rootScope.myID : updateMessage.user_id);
var toID = updateMessage.chat_id var toID = updateMessage.chat_id
? -updateMessage.chat_id ? -updateMessage.chat_id
: (isOut ? updateMessage.user_id : this.myID); : (isOut ? updateMessage.user_id : $rootScope.myID);
this.processUpdate({ this.processUpdate({
_: 'updateNewMessage', _: 'updateNewMessage',
@ -500,24 +493,31 @@ export class ApiUpdatesManager {
$rootScope.$broadcast('apiUpdate', update); $rootScope.$broadcast('apiUpdate', update);
} }
public attach() { public attach(state: Pick<ApiUpdatesManager['updatesState'], 'seq' | 'pts' | 'date'>) {
if(this.attached) return; if(this.attached) return;
this.attached = true; this.attached = true;
apiManager.setUpdatesProcessor(this.processUpdateMessage.bind(this)); apiManager.setUpdatesProcessor(this.processUpdateMessage.bind(this));
apiManager.invokeApi('updates.getState', {}, {noErrorBox: true}).then((stateResult: any) => {
this.updatesState.seq = stateResult.seq; if(!state) {
this.updatesState.pts = stateResult.pts; apiManager.invokeApi('updates.getState', {}, {noErrorBox: true}).then((stateResult: any) => {
this.updatesState.date = stateResult.date; this.updatesState.seq = stateResult.seq;
setTimeout(() => { this.updatesState.pts = stateResult.pts;
this.updatesState.syncLoading = false; this.updatesState.date = stateResult.date;
}, 1000); setTimeout(() => {
this.updatesState.syncLoading = false;
// updatesState.seq = 1 }, 1000);
// updatesState.pts = stateResult.pts - 5000
// updatesState.date = 1 // updatesState.seq = 1
// getDifference() // updatesState.pts = stateResult.pts - 5000
}); // updatesState.date = 1
// getDifference()
});
} else {
Object.assign(this.updatesState, state);
this.updatesState.syncLoading = false;
this.getDifference();
}
} }
} }

2
src/lib/appManagers/appChatsManager.ts

@ -72,7 +72,7 @@ export class AppChatsManager {
let titleWords = SearchIndexManager.cleanSearchText(apiChat.title || '', false).split(' '); let titleWords = SearchIndexManager.cleanSearchText(apiChat.title || '', false).split(' ');
let firstWord = titleWords.shift(); let firstWord = titleWords.shift();
let lastWord = titleWords.pop(); let lastWord = titleWords.pop();
apiChat.initials = firstWord.charAt(0) + (lastWord ? lastWord.charAt(0) : firstWord.charAt(1)); apiChat.initials = firstWord.charAt(0) + (lastWord ? lastWord.charAt(0) : '');
if(apiChat.pFlags === undefined) { if(apiChat.pFlags === undefined) {
apiChat.pFlags = {}; apiChat.pFlags = {};

68
src/lib/appManagers/appDialogsManager.ts

@ -384,8 +384,6 @@ export class AppDialogsManager {
public chatsArchivedContainer = document.getElementById('chats-archived-container') as HTMLDivElement; public chatsArchivedContainer = document.getElementById('chats-archived-container') as HTMLDivElement;
public chatsContainer = document.getElementById('chats-container') as HTMLDivElement; public chatsContainer = document.getElementById('chats-container') as HTMLDivElement;
private chatsArchivedOffsetIndex = 0;
private chatsOffsetIndex = 0;
private chatsPreloader: HTMLDivElement; private chatsPreloader: HTMLDivElement;
//private chatsLoadCount = 0; //private chatsLoadCount = 0;
//private loadDialogsPromise: Promise<any>; //private loadDialogsPromise: Promise<any>;
@ -544,10 +542,30 @@ export class AppDialogsManager {
} }
}); });
this.loadDialogs().then(result => { $rootScope.$on('peer_changed', (e: CustomEvent) => {
this.setPinnedDelimiter(); let peerID = e.detail;
//appSidebarLeft.onChatsScroll();
this.loadDialogs(true); let lastPeerID = this.lastActiveListElement && +this.lastActiveListElement.getAttribute('data-peerID');
if(this.lastActiveListElement && lastPeerID != peerID) {
this.lastActiveListElement.classList.remove('active');
this.lastActiveListElement = null;
}
if(lastPeerID != peerID) {
let dom = this.getDialogDom(peerID);
if(dom) {
this.lastActiveListElement = dom.listEl;
dom.listEl.classList.add('active');
}
}
});
appMessagesManager.loaded.then(() => {
this.loadDialogs().then(result => {
this.setPinnedDelimiter();
//appSidebarLeft.onChatsScroll();
this.loadDialogs(true);
});
}); });
} }
@ -559,30 +577,30 @@ export class AppDialogsManager {
if(this.loadDialogsPromise/* || 1 == 1 */) return this.loadDialogsPromise; if(this.loadDialogsPromise/* || 1 == 1 */) return this.loadDialogsPromise;
(archived ? this.chatsArchivedContainer : this.chatsContainer).append(this.chatsPreloader); (archived ? this.chatsArchivedContainer : this.chatsContainer).append(this.chatsPreloader);
//let offset = appMessagesManager.generateDialogIndex();/* appMessagesManager.dialogsNum */;
let offset = archived ? this.chatsArchivedOffsetIndex : this.chatsOffsetIndex;
//let offset = 0;
let scroll = archived ? this.scrollArchived : this.scroll; let storage = appMessagesManager.dialogsStorage[+archived] || [];
let offsetIndex = 0;
for(let i = storage.length - 1; i >= 0; --i) {
let dialog = storage[i];
if(this.getDialogDom(dialog.peerID)) {
offsetIndex = dialog.index;
break;
}
}
//let offset = storage[storage.length - 1]?.index || 0;
try { try {
console.time('getDialogs time'); console.time('getDialogs time');
let loadCount = 50/*this.chatsLoadCount */; let loadCount = 50/*this.chatsLoadCount */;
this.loadDialogsPromise = appMessagesManager.getConversations(offset, loadCount, +archived); this.loadDialogsPromise = appMessagesManager.getConversations(offsetIndex, loadCount, +archived);
let result = await this.loadDialogsPromise; let result = await this.loadDialogsPromise;
console.timeEnd('getDialogs time'); console.timeEnd('getDialogs time');
if(result && result.dialogs && result.dialogs.length) { if(result && result.dialogs && result.dialogs.length) {
let index = result.dialogs[result.dialogs.length - 1].index;
if(archived) this.chatsArchivedOffsetIndex = index;
else this.chatsOffsetIndex = index;
result.dialogs.forEach((dialog: any) => { result.dialogs.forEach((dialog: any) => {
this.addDialog(dialog); this.addDialog(dialog);
}); });
@ -598,7 +616,7 @@ export class AppDialogsManager {
this.archivedCount.innerText = '' + count; this.archivedCount.innerText = '' + count;
} */ } */
this.log('getDialogs ' + loadCount + ' dialogs by offset:', offset, result, this.scroll.length); this.log('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, this.scroll.length, archived);
this.scroll.onScroll(); this.scroll.onScroll();
} catch(err) { } catch(err) {
this.log.error(err); this.log.error(err);
@ -650,14 +668,14 @@ export class AppDialogsManager {
if(onFound) onFound(); if(onFound) onFound();
let peerID = +elem.getAttribute('data-peerID'); let peerID = +elem.getAttribute('data-peerID');
let lastMsgID = +elem.dataset.mid; let lastMsgID = +elem.dataset.mid || 0;
if(!samePeer) { if(!samePeer) {
elem.classList.add('active'); elem.classList.add('active');
this.lastActiveListElement = elem; this.lastActiveListElement = elem;
} }
result = appImManager.setPeer(peerID, lastMsgID, true); result = appImManager.setPeer(peerID, lastMsgID);
if(result instanceof Promise) { if(result instanceof Promise) {
this.lastGoodClickID = this.lastClickID; this.lastGoodClickID = this.lastClickID;
@ -721,7 +739,7 @@ export class AppDialogsManager {
public setPinnedDelimiter() { public setPinnedDelimiter() {
let index = -1; let index = -1;
let dialogs = appMessagesManager.dialogsStorage.dialogs[0]; let dialogs = appMessagesManager.dialogsStorage[0];
for(let dialog of dialogs) { for(let dialog of dialogs) {
if(dialog.pFlags?.pinned) { if(dialog.pFlags?.pinned) {
index++; index++;
@ -766,7 +784,7 @@ export class AppDialogsManager {
if(lastMessage._ == 'messageEmpty') { if(lastMessage._ == 'messageEmpty') {
dom.lastMessageSpan.innerHTML = ''; dom.lastMessageSpan.innerHTML = '';
dom.lastTimeSpan.innerHTML = ''; dom.lastTimeSpan.innerHTML = '';
dom.listEl.removeAttribute('data-mid'); delete dom.listEl.dataset.mid;
return; return;
} }
@ -853,10 +871,10 @@ export class AppDialogsManager {
dom.lastTimeSpan.innerHTML = timeStr; dom.lastTimeSpan.innerHTML = timeStr;
} else dom.lastTimeSpan.innerHTML = ''; } else dom.lastTimeSpan.innerHTML = '';
dom.listEl.setAttribute('data-mid', lastMessage.mid);
if(this.doms[peerID] || this.domsArchived[peerID]) { if(this.doms[peerID] || this.domsArchived[peerID]) {
this.setUnreadMessages(dialog); this.setUnreadMessages(dialog);
} else { // means search
dom.listEl.dataset.mid = lastMessage.mid;
} }
} }

750
src/lib/appManagers/appImManager.ts

File diff suppressed because it is too large Load Diff

173
src/lib/appManagers/appMediaViewer.ts

@ -171,7 +171,7 @@ export class AppMediaViewer {
mover = this.setNewMover(); mover = this.setNewMover();
} */ } */
///////this.log('setMoverToTarget', target, closing, wasActive, fromRight); this.log('setMoverToTarget', target, closing, wasActive, fromRight);
let realParent: HTMLDivElement; let realParent: HTMLDivElement;
@ -200,13 +200,38 @@ export class AppMediaViewer {
top = rect.top; top = rect.top;
} }
let aspecter: HTMLDivElement;
if(target instanceof HTMLImageElement || target instanceof HTMLVideoElement) {
if(mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter')) {
aspecter = mover.firstElementChild as HTMLDivElement;
let player = aspecter.querySelector('.ckin__player');
if(player) {
let video = player.firstElementChild as HTMLVideoElement;
aspecter.append(video);
player.remove();
}
if(!aspecter.style.cssText) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать
mover.classList.remove('active');
this.setFullAspect(aspecter, containerRect, rect);
void mover.offsetLeft; // reflow
mover.classList.add('active');
}
} else {
aspecter = document.createElement('div');
aspecter.classList.add('media-viewer-aspecter');
mover.prepend(aspecter);
}
aspecter.style.cssText = `width: ${rect.width}px; height: ${rect.height}px; transform: scale(${containerRect.width / rect.width}, ${containerRect.height / rect.height});`;
}
transform += `translate(${left}px,${top}px) `; transform += `translate(${left}px,${top}px) `;
mover.style.width = containerRect.width + 'px'; mover.style.width = containerRect.width + 'px';
mover.style.height = containerRect.height + 'px'; mover.style.height = containerRect.height + 'px';
mover.classList.remove('cover');
let scaleX = rect.width / containerRect.width; let scaleX = rect.width / containerRect.width;
let scaleY = rect.height / containerRect.height; let scaleY = rect.height / containerRect.height;
if(!wasActive) { if(!wasActive) {
@ -234,19 +259,15 @@ export class AppMediaViewer {
let video: HTMLVideoElement; let video: HTMLVideoElement;
if(target.tagName == 'DIV') { // means backgrounded with cover if(target.tagName == 'DIV') { // means backgrounded with cover
//img.style.objectFit = 'cover';
img = new Image(); img = new Image();
img.src = target.style.backgroundImage.slice(5, -2); img.src = target.style.backgroundImage.slice(5, -2);
//mover.classList.add('cover'); } else if(target instanceof HTMLImageElement) {
//mover.style.backgroundImage = target.style.backgroundImage;
} else if(target.tagName == 'IMG' || target.tagName == 'image') {
img = new Image(); img = new Image();
img.src = target instanceof SVGImageElement ? target.getAttributeNS(null, 'href') : (target as HTMLImageElement).src; img.src = target.src;
img.style.objectFit = 'contain'; } else if(target instanceof HTMLVideoElement) {
} else if(target.tagName == 'VIDEO') {
video = document.createElement('video'); video = document.createElement('video');
let source = document.createElement('source'); let source = document.createElement('source');
source.src = target.querySelector('source').src; source.src = target.querySelector('source')?.src;
video.append(source); video.append(source);
} else if(target instanceof SVGSVGElement) { } else if(target instanceof SVGSVGElement) {
let clipID = target.dataset.clipID; let clipID = target.dataset.clipID;
@ -298,12 +319,9 @@ export class AppMediaViewer {
mover.prepend(newSvg); mover.prepend(newSvg);
} }
if(img) { if(aspecter) {
img.style.borderRadius = borderRadius; aspecter.style.borderRadius = borderRadius;
mover.prepend(img); aspecter.append(img || video);
} else if(video) {
video.style.borderRadius = borderRadius;
mover.prepend(video);
} }
mover.style.display = ''; mover.style.display = '';
@ -330,15 +348,11 @@ export class AppMediaViewer {
if(mover.firstElementChild) { if(mover.firstElementChild) {
(mover.firstElementChild as HTMLElement).style.borderRadius = borderRadius; (mover.firstElementChild as HTMLElement).style.borderRadius = borderRadius;
} }
if(target.tagName == 'DIV') {
mover.classList.add('cover');
}
}, delay / 2); }, delay / 2);
setTimeout(() => { setTimeout(() => {
mover.innerHTML = ''; mover.innerHTML = '';
mover.classList.remove('moving', 'active', 'cover'); mover.classList.remove('moving', 'active');
mover.style.display = 'none'; mover.style.display = 'none';
}, delay); }, delay);
} }
@ -346,22 +360,60 @@ export class AppMediaViewer {
return () => { return () => {
mover.style.transform = `translate(${containerRect.left}px,${containerRect.top}px) scale(1,1)`; mover.style.transform = `translate(${containerRect.left}px,${containerRect.top}px) scale(1,1)`;
if(aspecter) {
this.setFullAspect(aspecter, containerRect, rect);
}
setTimeout(() => { setTimeout(() => {
mover.style.borderRadius = ''; mover.style.borderRadius = '';
if(mover.firstElementChild) { if(mover.firstElementChild) {
(mover.firstElementChild as HTMLElement).style.borderRadius = ''; (mover.firstElementChild as HTMLElement).style.borderRadius = '';
} }
mover.classList.remove('cover');
}, delay / 2); }, delay / 2);
mover.dataset.timeout = '' + setTimeout(() => {
mover.classList.remove('moving');
if(aspecter) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать
mover.classList.remove('active');
aspecter.style.cssText = '';
void mover.offsetLeft; // reflow
}
mover.classList.add('active');
delete mover.dataset.timeout;
}, delay);
if(path) { if(path) {
this.sizeTailPath(path, containerRect, scaleX, delay, true, isOut, borderRadius); this.sizeTailPath(path, containerRect, scaleX, delay, true, isOut, borderRadius);
} }
}; };
} }
private setFullAspect(aspecter: HTMLDivElement, containerRect: DOMRect, rect: DOMRect) {
let media = aspecter.firstElementChild;
let proportion: number;
if(media instanceof HTMLImageElement) {
proportion = media.naturalWidth / media.naturalHeight;
} else if(media instanceof HTMLVideoElement) {
proportion = media.videoWidth / media.videoHeight;
}
let {width, height} = rect;
if(proportion == 1) {
aspecter.style.cssText = '';
} else {
if(proportion > 0) {
width = height * proportion;
} else {
height = width * proportion;
}
aspecter.style.cssText = `width: ${width}px; height: ${height}px; transform: scale(${containerRect.width / width}, ${containerRect.height / height});`;
}
}
public sizeTailPath(path: SVGPathElement, rect: DOMRect, scaleX: number, delay: number, upscale: boolean, isOut: boolean, borderRadius: string) { public sizeTailPath(path: SVGPathElement, rect: DOMRect, scaleX: number, delay: number, upscale: boolean, isOut: boolean, borderRadius: string) {
let start = Date.now(); let start = Date.now();
let {width, height} = rect; let {width, height} = rect;
@ -393,8 +445,13 @@ export class AppMediaViewer {
public moveTheMover(mover: HTMLDivElement, toLeft = true) { public moveTheMover(mover: HTMLDivElement, toLeft = true) {
let windowW = appPhotosManager.windowW; let windowW = appPhotosManager.windowW;
//mover.classList.remove('active');
mover.classList.add('moving'); mover.classList.add('moving');
if(mover.dataset.timeout) { // и это тоже всё из-за скейла видео, так бы это не нужно было
clearTimeout(+mover.dataset.timeout);
}
let rect = mover.getBoundingClientRect(); let rect = mover.getBoundingClientRect();
let newTransform = mover.style.transform.replace(/translate\((.+?),/, (match, p1) => { let newTransform = mover.style.transform.replace(/translate\((.+?),/, (match, p1) => {
@ -617,30 +674,35 @@ export class AppMediaViewer {
if(useContainerAsTarget) target = target.querySelector('img, video') || target; if(useContainerAsTarget) target = target.querySelector('img, video') || target;
let afterTimeout = this.setMoverToTarget(target, false, fromRight); let afterTimeout = this.setMoverToTarget(target, false, fromRight);
//return; // set and don't move
//if(wasActive) return; //if(wasActive) return;
//return;
setTimeout(() => { setTimeout(() => {
afterTimeout(); afterTimeout();
//return; //return;
let video = mover.querySelector('video') || document.createElement('video'); let video = mover.querySelector('video') || document.createElement('video');
let source: HTMLSourceElement; let source = video.firstElementChild as HTMLSourceElement || document.createElement('source');
if(video.firstElementChild) {
source = video.firstElementChild as HTMLSourceElement;
}
if(media.type == 'gif') { if(media.type == 'gif') {
video.autoplay = true; video.autoplay = true;
} }
video.dataset.ckin = 'default'; let createPlayer = () => {
video.dataset.overlay = '1'; if(media.type != 'gif') {
video.dataset.ckin = 'default';
video.dataset.overlay = '1';
let player = new VideoPlayer(video, true);
/* player.wrapper.parentElement.append(video);
mover.append(player.wrapper); */
}
};
if(!source || !source.src) { if(!source || !source.src) {
let promise = appDocsManager.downloadDoc(media); let promise = appDocsManager.downloadDoc(media);
this.preloader.attach(mover, true, promise); this.preloader.attach(mover, true, promise);
promise.then(blob => { promise.then(() => {
if(this.currentMessageID != message.mid) { if(this.currentMessageID != message.mid) {
this.log.warn('media viewer changed video'); this.log.warn('media viewer changed video');
return; return;
@ -651,36 +713,27 @@ export class AppMediaViewer {
this.updateMediaSource(mover, url, 'source'); this.updateMediaSource(mover, url, 'source');
this.updateMediaSource(target, url, 'source'); this.updateMediaSource(target, url, 'source');
} else { } else {
let img = mover.firstElementChild; let aspecter = mover.firstElementChild;
if(img instanceof Image) { let img = aspecter.firstElementChild;
mover.removeChild(img); if(img instanceof HTMLImageElement) {
img.remove();
} }
source = document.createElement('source');
renderImageFromUrl(source, url); renderImageFromUrl(source, url);
source.type = media.mime_type; source.type = media.mime_type;
mover.prepend(video); if(!source.parentElement) {
video.append(source);
video.append(source); }
}
if(media.type != 'gif') { if(!video.parentElement) {
let player = new VideoPlayer(video, true); aspecter.prepend(video);
}
} }
});
} else if(media.type != 'gif') {
let player = new VideoPlayer(video, true);
}
createPlayer();
});
/* wrapVideo.call(this, media, mover, message, false, this.preloader).then(() => { } else createPlayer();
if(this.currentMessageID != message.mid) {
this.log.warn('media viewer changed video');
return;
}
}); */
}, 0); }, 0);
} else { } else {
let size = appPhotosManager.setAttachmentSize(media.id, container, maxWidth, maxHeight); let size = appPhotosManager.setAttachmentSize(media.id, container, maxWidth, maxHeight);
@ -688,7 +741,7 @@ export class AppMediaViewer {
if(useContainerAsTarget) target = target.querySelector('img, video') || target; if(useContainerAsTarget) target = target.querySelector('img, video') || target;
let afterTimeout = this.setMoverToTarget(target, false, fromRight); let afterTimeout = this.setMoverToTarget(target, false, fromRight);
//return; //return; // set and don't move
//if(wasActive) return; //if(wasActive) return;
setTimeout(() => { setTimeout(() => {
afterTimeout(); afterTimeout();
@ -709,10 +762,14 @@ export class AppMediaViewer {
this.updateMediaSource(target, url, 'image'); this.updateMediaSource(target, url, 'image');
this.updateMediaSource(mover, url, 'image'); this.updateMediaSource(mover, url, 'image');
} else { } else {
let image = mover.firstElementChild as HTMLImageElement || new Image(); let aspecter = mover.firstElementChild;
//image.src = url; let image = aspecter.firstElementChild as HTMLImageElement;
if(!image) {
image = new Image();
aspecter.append(image);
}
renderImageFromUrl(image, url); renderImageFromUrl(image, url);
mover.prepend(image);
} }
this.preloader.detach(); this.preloader.detach();

389
src/lib/appManagers/appMessagesManager.ts

@ -1,4 +1,4 @@
import { SearchIndexManager, $rootScope, copy, tsNow, safeReplaceObject, dT, _, listMergeSorted, deepEqual, langPack } from "../utils"; import { $rootScope, copy, tsNow, safeReplaceObject, dT, _, listMergeSorted, deepEqual, langPack } from "../utils";
import appMessagesIDsManager from "./appMessagesIDsManager"; import appMessagesIDsManager from "./appMessagesIDsManager";
import appChatsManager from "./appChatsManager"; import appChatsManager from "./appChatsManager";
import appUsersManager from "./appUsersManager"; import appUsersManager from "./appUsersManager";
@ -9,7 +9,7 @@ import apiUpdatesManager from "./apiUpdatesManager";
import appPhotosManager from "./appPhotosManager"; import appPhotosManager from "./appPhotosManager";
import AppStorage from '../storage'; import AppStorage from '../storage';
import AppPeersManager from "./appPeersManager"; import appPeersManager from "./appPeersManager";
import ServerTimeManager from "../mtproto/serverTimeManager"; import ServerTimeManager from "../mtproto/serverTimeManager";
import apiFileManager from "../mtproto/apiFileManager"; import apiFileManager from "../mtproto/apiFileManager";
import appDocsManager from "./appDocsManager"; import appDocsManager from "./appDocsManager";
@ -64,20 +64,13 @@ export type Dialog = {
export class AppMessagesManager { export class AppMessagesManager {
public messagesStorage: any = {}; public messagesStorage: any = {};
public messagesForDialogs: any = {};
public groupedMessagesStorage: {[groupID: string]: any} = {}; // will be used for albums public groupedMessagesStorage: {[groupID: string]: any} = {}; // will be used for albums
public historiesStorage: { public historiesStorage: {
[peerID: string]: HistoryStorage [peerID: string]: HistoryStorage
} = {}; } = {};
public dialogsStorage: { public dialogsStorage: {
count: number, [folderID: number]: Dialog[]
dialogs: { } = {};
[folderID: number]: Dialog[]
}
} = {
count: null,
dialogs: {}
};
public pendingByRandomID: {[randomID: string]: [number, number]} = {}; public pendingByRandomID: {[randomID: string]: [number, number]} = {};
public pendingByMessageID: any = {}; public pendingByMessageID: any = {};
public pendingAfterMsgs: any = {}; public pendingAfterMsgs: any = {};
@ -86,9 +79,6 @@ export class AppMessagesManager {
public tempID = -1; public tempID = -1;
public tempFinalizeCallbacks: any = {}; public tempFinalizeCallbacks: any = {};
public dialogsIndex: any = SearchIndexManager.createIndex();
public cachedResults: any = {query: false};
public lastSearchFilter: any = {}; public lastSearchFilter: any = {};
public lastSearchResults: any = []; public lastSearchResults: any = [];
@ -96,10 +86,6 @@ export class AppMessagesManager {
public fetchSingleMessagesTimeout = 0; public fetchSingleMessagesTimeout = 0;
private fetchSingleMessagesPromise: Promise<void> = null; private fetchSingleMessagesPromise: Promise<void> = null;
public incrementedMessageViews: any = {};
public needIncrementMessageViews: any = [];
public incrementMessageViewsTimeout: any = false;
public maxSeenID = 0; public maxSeenID = 0;
public allDialogsLoaded: {[folder_id: number]: boolean} = {}; public allDialogsLoaded: {[folder_id: number]: boolean} = {};
@ -116,16 +102,9 @@ export class AppMessagesManager {
public newDialogsToHandle: {[peerID: string]: {reload: true} | Dialog} = {}; public newDialogsToHandle: {[peerID: string]: {reload: true} | Dialog} = {};
public newUpdatesAfterReloadToHandle: any = {}; public newUpdatesAfterReloadToHandle: any = {};
public fwdMessagesPluralize = _('conversation_forwarded_X_messages'); public loaded: Promise<any> = null;
public gameScorePluralize = _('conversation_scored_X');
constructor() { constructor() {
AppStorage.get<number>('max_seen_msg').then((maxID) => {
if(maxID && !appMessagesIDsManager.getMessageIDInfo(maxID)[1]) {
this.maxSeenID = maxID;
}
});
$rootScope.$on('apiUpdate', (e: CustomEvent) => { $rootScope.$on('apiUpdate', (e: CustomEvent) => {
let update: any = e.detail; let update: any = e.detail;
// if(update._ != 'updateUserStatus') { // if(update._ != 'updateUserStatus') {
@ -159,7 +138,7 @@ export class AppMessagesManager {
if(draft && draft.date) { if(draft && draft.date) {
topDate = draft.date; topDate = draft.date;
} else { } else {
var channelID = AppPeersManager.isChannel(peerID) ? -peerID : 0 var channelID = appPeersManager.isChannel(peerID) ? -peerID : 0
var topDate = this.getMessage(dialog.top_message).date; var topDate = this.getMessage(dialog.top_message).date;
if(channelID) { if(channelID) {
@ -183,6 +162,94 @@ export class AppMessagesManager {
}); });
} }
}); });
this.loaded = new Promise((resolve, reject) => {
AppStorage.get<{
dialogs: Dialog[],
allDialogsLoaded: AppMessagesManager['allDialogsLoaded'],
peers: any[],
messages: any[],
updates: any,
maxSeenMsgID: number
}>('state').then(({dialogs, allDialogsLoaded, peers, messages, maxSeenMsgID, updates}) => {
console.log('state res', dialogs, messages);
if(maxSeenMsgID && !appMessagesIDsManager.getMessageIDInfo(maxSeenMsgID)[1]) {
this.maxSeenID = maxSeenMsgID;
}
//return resolve();
if(peers) {
for(let peerID in peers) {
let peer = peers[peerID];
if(+peerID < 0) appChatsManager.saveApiChat(peer);
else appUsersManager.saveApiUser(peer);
}
}
if(messages) {
this.saveMessages(messages);
}
if(allDialogsLoaded) {
this.allDialogsLoaded = allDialogsLoaded;
}
if(dialogs) {
dialogs.forEachReverse(dialog => {
this.saveConversation(dialog);
});
}
apiUpdatesManager.attach(updates ?? null);
resolve();
}).catch(resolve);
});
setInterval(() => this.saveState(), 10000);
}
public saveState() {
let messages: any[] = [];
let dialogs: Dialog[] = [];
let peers: {[peerID: number]: any} = {};
for(let folderID in this.dialogsStorage) {
for(let dialog of this.dialogsStorage[folderID]) {
let message = this.getMessage(dialog.top_message);
if(message._ != 'messageEmpty' && message.id > 0) {
messages.push(message);
if(message.fromID != dialog.peerID) {
peers[message.fromID] = appPeersManager.getPeer(message.fromID);
}
}
dialogs.push(dialog);
peers[dialog.peerID] = appPeersManager.getPeer(dialog.peerID);
}
}
let us = apiUpdatesManager.updatesState;
let updates = {
seq: us.seq,
pts: us.pts,
date: us.date
};
AppStorage.set({
state: {
dialogs,
messages,
allDialogsLoaded: this.allDialogsLoaded,
peers,
updates,
maxSeenMsgID: this.maxSeenID
}
});
} }
public getInputEntities(entities: any) { public getInputEntities(entities: any) {
@ -240,7 +307,7 @@ export class AppMessagesManager {
return apiManager.invokeApi('messages.editMessage', { return apiManager.invokeApi('messages.editMessage', {
flags: flags, flags: flags,
peer: AppPeersManager.getInputPeerByID(peerID), peer: appPeersManager.getInputPeerByID(peerID),
id: appMessagesIDsManager.getMessageLocalID(messageID), id: appMessagesIDsManager.getMessageLocalID(messageID),
message: text, message: text,
media: message.media, media: message.media,
@ -260,22 +327,22 @@ export class AppMessagesManager {
}); });
} }
public sendText(peerID: number, text: string, options: { public sendText(peerID: number, text: string, options: Partial<{
entities?: any[], entities: any[],
replyToMsgID?: number, replyToMsgID: number,
viaBotID?: number, viaBotID: number,
queryID?: number, queryID: number,
resultID?: number, resultID: number,
noWebPage?: boolean, noWebPage: boolean,
reply_markup?: any, reply_markup: any,
clearDraft?: boolean, clearDraft: boolean,
webPage?: any webPage: any
} = {}) { }> = {}) {
if(typeof(text) != 'string') { if(typeof(text) != 'string') {
return; return;
} }
peerID = AppPeersManager.getPeerMigratedTo(peerID) || peerID; peerID = appPeersManager.getPeerMigratedTo(peerID) || peerID;
var entities = options.entities || []; var entities = options.entities || [];
if(!options.viaBotID) { if(!options.viaBotID) {
@ -293,8 +360,8 @@ export class AppMessagesManager {
var flags = 0; var flags = 0;
var pFlags: any = {}; var pFlags: any = {};
var replyToMsgID = options.replyToMsgID; var replyToMsgID = options.replyToMsgID;
var isChannel = AppPeersManager.isChannel(peerID); var isChannel = appPeersManager.isChannel(peerID);
var isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID); var isMegagroup = isChannel && appPeersManager.isMegagroup(peerID);
var asChannel = isChannel && !isMegagroup ? true : false; var asChannel = isChannel && !isMegagroup ? true : false;
var message: any; var message: any;
let noWebPage = options.noWebPage || false; let noWebPage = options.noWebPage || false;
@ -329,7 +396,7 @@ export class AppMessagesManager {
_: 'message', _: 'message',
id: messageID, id: messageID,
from_id: fromID, from_id: fromID,
to_id: AppPeersManager.getOutputPeer(peerID), to_id: appPeersManager.getOutputPeer(peerID),
flags: flags, flags: flags,
pFlags: pFlags, pFlags: pFlags,
date: tsNow(true) + serverTimeManager.serverTimeOffset, date: tsNow(true) + serverTimeManager.serverTimeOffset,
@ -387,7 +454,7 @@ export class AppMessagesManager {
if(options.viaBotID) { if(options.viaBotID) {
apiPromise = apiManager.invokeApi('messages.sendInlineBotResult', { apiPromise = apiManager.invokeApi('messages.sendInlineBotResult', {
flags: flags, flags: flags,
peer: AppPeersManager.getInputPeerByID(peerID), peer: appPeersManager.getInputPeerByID(peerID),
random_id: randomID, random_id: randomID,
reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID), reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID),
query_id: options.queryID, query_id: options.queryID,
@ -401,7 +468,7 @@ export class AppMessagesManager {
apiPromise = apiManager.invokeApi('messages.sendMessage', { apiPromise = apiManager.invokeApi('messages.sendMessage', {
flags: flags, flags: flags,
no_webpage: noWebPage, no_webpage: noWebPage,
peer: AppPeersManager.getInputPeerByID(peerID), peer: appPeersManager.getInputPeerByID(peerID),
message: text, message: text,
random_id: randomID, random_id: randomID,
reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID), reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID),
@ -490,7 +557,7 @@ export class AppMessagesManager {
duration: number, duration: number,
background: boolean background: boolean
}> = {}) { }> = {}) {
peerID = AppPeersManager.getPeerMigratedTo(peerID) || peerID; peerID = appPeersManager.getPeerMigratedTo(peerID) || peerID;
var messageID = this.tempID--; var messageID = this.tempID--;
var randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]; var randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)];
var randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(); var randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString();
@ -498,8 +565,8 @@ export class AppMessagesManager {
var flags = 0; var flags = 0;
var pFlags: any = {}; var pFlags: any = {};
var replyToMsgID = options.replyToMsgID; var replyToMsgID = options.replyToMsgID;
var isChannel = AppPeersManager.isChannel(peerID); var isChannel = appPeersManager.isChannel(peerID);
var isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID); var isMegagroup = isChannel && appPeersManager.isMegagroup(peerID);
var asChannel = isChannel && !isMegagroup ? true : false; var asChannel = isChannel && !isMegagroup ? true : false;
var attachType: string, apiFileName: string; var attachType: string, apiFileName: string;
@ -651,7 +718,7 @@ export class AppMessagesManager {
_: 'message', _: 'message',
id: messageID, id: messageID,
from_id: fromID, from_id: fromID,
to_id: AppPeersManager.getOutputPeer(peerID), to_id: appPeersManager.getOutputPeer(peerID),
flags: flags, flags: flags,
pFlags: pFlags, pFlags: pFlags,
date: date, date: date,
@ -688,7 +755,7 @@ export class AppMessagesManager {
flags: flags, flags: flags,
background: options.background, background: options.background,
clear_draft: true, clear_draft: true,
peer: AppPeersManager.getInputPeerByID(peerID), peer: appPeersManager.getInputPeerByID(peerID),
media: inputMedia, media: inputMedia,
message: caption, message: caption,
random_id: randomID, random_id: randomID,
@ -821,14 +888,14 @@ export class AppMessagesManager {
objectURL: string, objectURL: string,
}>[] }>[]
}> = {}) { }> = {}) {
peerID = AppPeersManager.getPeerMigratedTo(peerID) || peerID; peerID = appPeersManager.getPeerMigratedTo(peerID) || peerID;
let groupID: number; let groupID: number;
let historyStorage = this.historiesStorage[peerID] ?? (this.historiesStorage[peerID] = {count: null, history: [], pending: []}); let historyStorage = this.historiesStorage[peerID] ?? (this.historiesStorage[peerID] = {count: null, history: [], pending: []});
let flags = 0; let flags = 0;
let pFlags: any = {}; let pFlags: any = {};
let replyToMsgID = options.replyToMsgID; let replyToMsgID = options.replyToMsgID;
let isChannel = AppPeersManager.isChannel(peerID); let isChannel = appPeersManager.isChannel(peerID);
let isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID); let isMegagroup = isChannel && appPeersManager.isMegagroup(peerID);
let asChannel = isChannel && !isMegagroup ? true : false; let asChannel = isChannel && !isMegagroup ? true : false;
let caption = options.caption || ''; let caption = options.caption || '';
@ -949,7 +1016,7 @@ export class AppMessagesManager {
id: messageID, id: messageID,
from_id: fromID, from_id: fromID,
grouped_id: groupID, grouped_id: groupID,
to_id: AppPeersManager.getOutputPeer(peerID), to_id: appPeersManager.getOutputPeer(peerID),
flags: flags, flags: flags,
pFlags: pFlags, pFlags: pFlags,
date: date, date: date,
@ -987,7 +1054,7 @@ export class AppMessagesManager {
let uploaded = false, let uploaded = false,
uploadPromise: ReturnType<typeof apiFileManager.uploadFile> = null; uploadPromise: ReturnType<typeof apiFileManager.uploadFile> = null;
let inputPeer = AppPeersManager.getInputPeerByID(peerID); let inputPeer = appPeersManager.getInputPeerByID(peerID);
let invoke = (multiMedia: any[]) => { let invoke = (multiMedia: any[]) => {
appImManager.setTyping('sendMessageCancelAction'); appImManager.setTyping('sendMessageCancelAction');
@ -1129,9 +1196,7 @@ export class AppMessagesManager {
} }
public getConversations(offsetIndex?: number, limit = 20, folderID = 0) { public getConversations(offsetIndex?: number, limit = 20, folderID = 0) {
let curDialogStorage = this.dialogsStorage.dialogs[folderID] ?? (this.dialogsStorage.dialogs[folderID] = []); let curDialogStorage = this.dialogsStorage[folderID] ?? (this.dialogsStorage[folderID] = []);
this.cachedResults.query = false;
let offset = 0; let offset = 0;
if(offsetIndex > 0) { if(offsetIndex > 0) {
@ -1150,7 +1215,7 @@ export class AppMessagesManager {
} }
return this.getTopMessages(limit, folderID).then(count => { return this.getTopMessages(limit, folderID).then(count => {
let curDialogStorage = this.dialogsStorage.dialogs[folderID]; let curDialogStorage = this.dialogsStorage[folderID];
offset = 0; offset = 0;
if(offsetIndex > 0) { if(offsetIndex > 0) {
@ -1171,12 +1236,12 @@ export class AppMessagesManager {
} }
public getTopMessages(limit: number, folderID: number): Promise<number> { public getTopMessages(limit: number, folderID: number): Promise<number> {
var dialogs = this.dialogsStorage.dialogs[folderID]; const dialogs = this.dialogsStorage[folderID];
var offsetDate = 0; let offsetID = 0;
var offsetID = 0; let offsetDate = 0;
var offsetPeerID = 0; let offsetPeerID = 0;
var offsetIndex = 0; let offsetIndex = 0;
var flags = 0; let flags = 0;
if(this.dialogsOffsetDate[folderID]) { if(this.dialogsOffsetDate[folderID]) {
offsetDate = this.dialogsOffsetDate[folderID] + serverTimeManager.serverTimeOffset; offsetDate = this.dialogsOffsetDate[folderID] + serverTimeManager.serverTimeOffset;
@ -1196,7 +1261,7 @@ export class AppMessagesManager {
folder_id: folderID, folder_id: folderID,
offset_date: offsetDate, offset_date: offsetDate,
offset_id: appMessagesIDsManager.getMessageLocalID(offsetID), offset_id: appMessagesIDsManager.getMessageLocalID(offsetID),
offset_peer: AppPeersManager.getInputPeerByID(offsetPeerID), offset_peer: appPeersManager.getInputPeerByID(offsetPeerID),
limit: limit, limit: limit,
hash: hash hash: hash
}, { }, {
@ -1230,7 +1295,7 @@ export class AppMessagesManager {
} }
if(!maxSeenIdIncremented && if(!maxSeenIdIncremented &&
!AppPeersManager.isChannel(AppPeersManager.getPeerID(dialog.peer))) { !appPeersManager.isChannel(appPeersManager.getPeerID(dialog.peer))) {
this.incrementMaxSeenID(dialog.top_message); this.incrementMaxSeenID(dialog.top_message);
maxSeenIdIncremented = true; maxSeenIdIncremented = true;
} }
@ -1267,7 +1332,7 @@ export class AppMessagesManager {
public forwardMessages(peerID: number, mids: number[], options: Partial<{ public forwardMessages(peerID: number, mids: number[], options: Partial<{
withMyScore: boolean withMyScore: boolean
}> = {}) { }> = {}) {
peerID = AppPeersManager.getPeerMigratedTo(peerID) || peerID; peerID = appPeersManager.getPeerMigratedTo(peerID) || peerID;
mids = mids.sort((a, b) => a - b); mids = mids.sort((a, b) => a - b);
var flags = 0; var flags = 0;
@ -1293,10 +1358,10 @@ export class AppMessagesManager {
let promise = apiManager.invokeApi('messages.forwardMessages', { let promise = apiManager.invokeApi('messages.forwardMessages', {
flags: flags, flags: flags,
from_peer: AppPeersManager.getInputPeerByID(-channelID), from_peer: appPeersManager.getInputPeerByID(-channelID),
id: msgIDs, id: msgIDs,
random_id: randomIDs, random_id: randomIDs,
to_peer: AppPeersManager.getInputPeerByID(peerID) to_peer: appPeersManager.getInputPeerByID(peerID)
}, sentRequestOptions).then((updates) => { }, sentRequestOptions).then((updates) => {
apiUpdatesManager.processUpdateMessage(updates); apiUpdatesManager.processUpdateMessage(updates);
}, () => {}).then(() => { }, () => {}).then(() => {
@ -1329,7 +1394,7 @@ export class AppMessagesManager {
} }
public generateIndexForDialog(dialog: Dialog) { public generateIndexForDialog(dialog: Dialog) {
let channelID = AppPeersManager.isChannel(dialog.peerID) ? -dialog.peerID : 0; let channelID = appPeersManager.isChannel(dialog.peerID) ? -dialog.peerID : 0;
let mid = appMessagesIDsManager.getFullMessageID(dialog.top_message, channelID); let mid = appMessagesIDsManager.getFullMessageID(dialog.top_message, channelID);
let message = this.getMessage(mid); let message = this.getMessage(mid);
@ -1354,15 +1419,15 @@ export class AppMessagesManager {
} }
public pushDialogToStorage(dialog: Dialog, offsetDate?: number) { public pushDialogToStorage(dialog: Dialog, offsetDate?: number) {
let dialogs = this.dialogsStorage.dialogs[dialog.folder_id] ?? (this.dialogsStorage.dialogs[dialog.folder_id] = []); let dialogs = this.dialogsStorage[dialog.folder_id] ?? (this.dialogsStorage[dialog.folder_id] = []);
let pos = dialogs.findIndex(d => d.peerID == dialog.peerID); let pos = dialogs.findIndex(d => d.peerID == dialog.peerID);
if(pos !== -1) { if(pos !== -1) {
dialogs.splice(pos, 1); dialogs.splice(pos, 1);
} }
if(offsetDate && if(offsetDate &&
!dialog.pFlags.pinned && !dialog.pFlags.pinned &&
(!this.dialogsOffsetDate[dialog.folder_id] || offsetDate < this.dialogsOffsetDate[dialog.folder_id])) { (!this.dialogsOffsetDate[dialog.folder_id] || offsetDate < this.dialogsOffsetDate[dialog.folder_id])) {
if(pos !== -1) { if(pos !== -1) {
// So the dialog jumped to the last position // So the dialog jumped to the last position
return false; return false;
@ -1395,7 +1460,7 @@ export class AppMessagesManager {
} }
public getMessagePeer(message: any): number { public getMessagePeer(message: any): number {
var toID = message.to_id && AppPeersManager.getPeerID(message.to_id) || 0; var toID = message.to_id && appPeersManager.getPeerID(message.to_id) || 0;
if(toID < 0) { if(toID < 0) {
return toID; return toID;
@ -1406,7 +1471,7 @@ export class AppMessagesManager {
} }
public getDialogByPeerID(peerID: number): [Dialog, number] | [] { public getDialogByPeerID(peerID: number): [Dialog, number] | [] {
let dialogs = this.dialogsStorage.dialogs; let dialogs = this.dialogsStorage;
for(let folderID in dialogs) { for(let folderID in dialogs) {
let index = dialogs[folderID].findIndex(dialog => dialog.peerID == peerID); let index = dialogs[folderID].findIndex(dialog => dialog.peerID == peerID);
if(index !== -1) { if(index !== -1) {
@ -1418,7 +1483,7 @@ export class AppMessagesManager {
} }
public reloadConversation(peerID: number | number[]) { public reloadConversation(peerID: number | number[]) {
let peers = [].concat(peerID).map(peerID => AppPeersManager.getInputPeerByID(peerID)); let peers = [].concat(peerID).map(peerID => appPeersManager.getInputPeerByID(peerID));
console.log('will reloadConversation', peerID); console.log('will reloadConversation', peerID);
@ -1456,7 +1521,7 @@ export class AppMessagesManager {
} }
public async flushHistory(peerID: number, justClear: boolean) { public async flushHistory(peerID: number, justClear: boolean) {
if(AppPeersManager.isChannel(peerID)) { if(appPeersManager.isChannel(peerID)) {
let promise = this.getHistory(peerID, 0, 1); let promise = this.getHistory(peerID, 0, 1);
let historyResult = promise instanceof Promise ? await promise : promise; let historyResult = promise instanceof Promise ? await promise : promise;
@ -1480,7 +1545,7 @@ export class AppMessagesManager {
}); });
} }
return this.doFlushHistory(AppPeersManager.getInputPeerByID(peerID), justClear).then(() => { return this.doFlushHistory(appPeersManager.getInputPeerByID(peerID), justClear).then(() => {
delete this.historiesStorage[peerID]; delete this.historiesStorage[peerID];
for(let mid in this.messagesStorage) { for(let mid in this.messagesStorage) {
let message = this.messagesStorage[mid]; let message = this.messagesStorage[mid];
@ -1494,7 +1559,7 @@ export class AppMessagesManager {
} else { } else {
let foundDialog = this.getDialogByPeerID(peerID); let foundDialog = this.getDialogByPeerID(peerID);
if(foundDialog[0]) { if(foundDialog[0]) {
this.dialogsStorage.dialogs[foundDialog[0].folder_id].splice(foundDialog[1], 1); this.dialogsStorage[foundDialog[0].folder_id].splice(foundDialog[1], 1);
} }
$rootScope.$broadcast('dialog_drop', {peerID: peerID}); $rootScope.$broadcast('dialog_drop', {peerID: peerID});
@ -1559,9 +1624,9 @@ export class AppMessagesManager {
if(fwdHeader) { if(fwdHeader) {
if(peerID == appUsersManager.getSelf().id) { if(peerID == appUsersManager.getSelf().id) {
if(fwdHeader.saved_from_peer && fwdHeader.saved_from_msg_id) { if(fwdHeader.saved_from_peer && fwdHeader.saved_from_msg_id) {
var savedFromPeerID = AppPeersManager.getPeerID(fwdHeader.saved_from_peer); var savedFromPeerID = appPeersManager.getPeerID(fwdHeader.saved_from_peer);
var savedFromMid = appMessagesIDsManager.getFullMessageID(fwdHeader.saved_from_msg_id, var savedFromMid = appMessagesIDsManager.getFullMessageID(fwdHeader.saved_from_msg_id,
AppPeersManager.isChannel(savedFromPeerID) ? -savedFromPeerID : 0); appPeersManager.isChannel(savedFromPeerID) ? -savedFromPeerID : 0);
apiMessage.savedFrom = savedFromPeerID + '_' + savedFromMid; apiMessage.savedFrom = savedFromPeerID + '_' + savedFromMid;
} }
@ -1834,7 +1899,7 @@ export class AppMessagesManager {
folder_peers: peerIDs.map(peerID => { folder_peers: peerIDs.map(peerID => {
return { return {
_: 'inputFolderPeer', _: 'inputFolderPeer',
peer: AppPeersManager.getInputPeerByID(peerID), peer: appPeersManager.getInputPeerByID(peerID),
folder_id: folderID folder_id: folderID
}; };
}) })
@ -1850,7 +1915,7 @@ export class AppMessagesManager {
let peer = { let peer = {
_: 'inputDialogPeer', _: 'inputDialogPeer',
peer: AppPeersManager.getInputPeerByID(peerID) peer: appPeersManager.getInputPeerByID(peerID)
}; };
let flags = dialog.pFlags?.pinned ? 0 : 1; let flags = dialog.pFlags?.pinned ? 0 : 1;
@ -1874,7 +1939,7 @@ export class AppMessagesManager {
let peer = { let peer = {
_: 'inputDialogPeer', _: 'inputDialogPeer',
peer: AppPeersManager.getInputPeerByID(peerID) peer: appPeersManager.getInputPeerByID(peerID)
}; };
let flags = dialog.pFlags?.unread_mark ? 0 : 1; let flags = dialog.pFlags?.unread_mark ? 0 : 1;
@ -1906,7 +1971,7 @@ export class AppMessagesManager {
setTimeout(() => { setTimeout(() => {
var foundDialog = this.getDialogByPeerID(migrateFrom); var foundDialog = this.getDialogByPeerID(migrateFrom);
if(foundDialog.length) { if(foundDialog.length) {
this.dialogsStorage.dialogs[foundDialog[0].folder_id].splice(foundDialog[1], 1); this.dialogsStorage[foundDialog[0].folder_id].splice(foundDialog[1], 1);
$rootScope.$broadcast('dialog_drop', {peerID: migrateFrom, dialog: foundDialog[0]}); $rootScope.$broadcast('dialog_drop', {peerID: migrateFrom, dialog: foundDialog[0]});
} }
@ -1969,7 +2034,7 @@ export class AppMessagesManager {
var updatedDialogs: {[peerID: number]: Dialog} = {}; var updatedDialogs: {[peerID: number]: Dialog} = {};
var hasUpdated = false; var hasUpdated = false;
dialogsResult.dialogs.forEach((dialog: any) => { dialogsResult.dialogs.forEach((dialog: any) => {
var peerID = AppPeersManager.getPeerID(dialog.peer); var peerID = appPeersManager.getPeerID(dialog.peer);
var topMessage = dialog.top_message; var topMessage = dialog.top_message;
var topPendingMesage = this.pendingTopMsgs[peerID]; var topPendingMesage = this.pendingTopMsgs[peerID];
if(topPendingMesage) { if(topPendingMesage) {
@ -1991,7 +2056,6 @@ export class AppMessagesManager {
this.saveConversation(dialog); this.saveConversation(dialog);
if(wasDialogBefore) { if(wasDialogBefore) {
this.clearDialogCache(topMessage);
$rootScope.$broadcast('dialog_top', dialog); $rootScope.$broadcast('dialog_top', dialog);
} else { } else {
updatedDialogs[peerID] = dialog; updatedDialogs[peerID] = dialog;
@ -2000,7 +2064,7 @@ export class AppMessagesManager {
} else { } else {
var foundDialog = this.getDialogByPeerID(peerID); var foundDialog = this.getDialogByPeerID(peerID);
if(foundDialog.length) { if(foundDialog.length) {
this.dialogsStorage.dialogs[foundDialog[0].folder_id].splice(foundDialog[1], 1); this.dialogsStorage[foundDialog[0].folder_id].splice(foundDialog[1], 1);
$rootScope.$broadcast('dialog_drop', {peerID: peerID, dialog: foundDialog[0]}); $rootScope.$broadcast('dialog_drop', {peerID: peerID, dialog: foundDialog[0]});
} }
} }
@ -2020,20 +2084,13 @@ export class AppMessagesManager {
} }
} }
public clearDialogCache(msgID: number) {
delete this.messagesForDialogs[msgID];
}
public saveConversation(dialog: Dialog) { public saveConversation(dialog: Dialog) {
var peerID = AppPeersManager.getPeerID(dialog.peer); var peerID = appPeersManager.getPeerID(dialog.peer);
if(!peerID) { if(!peerID) {
return false; return false;
} }
var channelID = AppPeersManager.isChannel(peerID) ? -peerID : 0; var channelID = appPeersManager.isChannel(peerID) ? -peerID : 0;
var peerText = AppPeersManager.getPeerSearchText(peerID);
SearchIndexManager.indexObject(peerID, peerText, this.dialogsIndex);
//var isMegagroup = AppPeersManager.isMegagroup(channelID);
if(dialog.top_message) { if(dialog.top_message) {
var mid = appMessagesIDsManager.getFullMessageID(dialog.top_message, channelID); var mid = appMessagesIDsManager.getFullMessageID(dialog.top_message, channelID);
var message = this.getMessage(mid); var message = this.getMessage(mid);
@ -2044,7 +2101,7 @@ export class AppMessagesManager {
id: mid, id: mid,
mid: mid, mid: mid,
from_id: appUsersManager.getSelf().id, from_id: appUsersManager.getSelf().id,
to_id: AppPeersManager.getOutputPeer(peerID), to_id: appPeersManager.getOutputPeer(peerID),
deleted: true, deleted: true,
flags: 0, flags: 0,
pFlags: {unread: false, out: true}, pFlags: {unread: false, out: true},
@ -2053,12 +2110,11 @@ export class AppMessagesManager {
} }
this.saveMessages([message]); this.saveMessages([message]);
} }
var offsetDate = message.date;
if(!channelID && peerID < 0) { if(!channelID && peerID < 0) {
var chat = appChatsManager.getChat(-peerID) var chat = appChatsManager.getChat(-peerID)
if(chat && chat.migrated_to && chat.pFlags.deactivated) { if(chat && chat.migrated_to && chat.pFlags.deactivated) {
var migratedToPeer = AppPeersManager.getPeerID(chat.migrated_to) var migratedToPeer = appPeersManager.getPeerID(chat.migrated_to)
this.migratedFromTo[peerID] = migratedToPeer; this.migratedFromTo[peerID] = migratedToPeer;
this.migratedToFrom[migratedToPeer] = peerID; this.migratedToFrom[migratedToPeer] = peerID;
return; return;
@ -2073,7 +2129,7 @@ export class AppMessagesManager {
dialog.peerID = peerID; dialog.peerID = peerID;
this.generateIndexForDialog(dialog); this.generateIndexForDialog(dialog);
this.pushDialogToStorage(dialog, offsetDate); this.pushDialogToStorage(dialog, message.date);
// Because we saved message without dialog present // Because we saved message without dialog present
if(message.mid > 0) { if(message.mid > 0) {
@ -2093,12 +2149,6 @@ export class AppMessagesManager {
} }
} }
//NotificationsManager.savePeerSettings(peerID, dialog.notify_settings); // warning
/* if(dialog.pts || dialog.pFlags.pts) {
console.warn('dialog pts!', dialog, dialog.pts);
} */
if(channelID && dialog.pts) { if(channelID && dialog.pts) {
apiUpdatesManager.addChannelState(channelID, dialog.pts); apiUpdatesManager.addChannelState(channelID, dialog.pts);
} }
@ -2190,8 +2240,7 @@ export class AppMessagesManager {
var foundMsgs: number[] = []; var foundMsgs: number[] = [];
var useSearchCache = !query; var useSearchCache = !query;
var newSearchFilter = {peer: peerID, filter: inputFilter}; var newSearchFilter = {peer: peerID, filter: inputFilter};
var sameSearchCache = useSearchCache var sameSearchCache = useSearchCache && deepEqual(this.lastSearchFilter, newSearchFilter);
&& deepEqual(this.lastSearchFilter, newSearchFilter); //angular.equals(this.lastSearchFilter, newSearchFilter);
if(useSearchCache && !sameSearchCache) { if(useSearchCache && !sameSearchCache) {
// console.warn(dT(), 'new search filter', lastSearchFilter, newSearchFilter) // console.warn(dT(), 'new search filter', lastSearchFilter, newSearchFilter)
@ -2313,7 +2362,7 @@ export class AppMessagesManager {
if(peerID || !query) { if(peerID || !query) {
apiPromise = apiManager.invokeApi('messages.search', { apiPromise = apiManager.invokeApi('messages.search', {
flags: 0, flags: 0,
peer: AppPeersManager.getInputPeerByID(peerID), peer: appPeersManager.getInputPeerByID(peerID),
q: query || '', q: query || '',
filter: inputFilter || {_: 'inputMessagesFilterEmpty'}, filter: inputFilter || {_: 'inputMessagesFilterEmpty'},
min_date: 0, min_date: 0,
@ -2342,7 +2391,7 @@ export class AppMessagesManager {
apiPromise = apiManager.invokeApi('messages.searchGlobal', { apiPromise = apiManager.invokeApi('messages.searchGlobal', {
q: query, q: query,
offset_rate: offsetRate, offset_rate: offsetRate,
offset_peer: AppPeersManager.getInputPeerByID(offsetPeerID), offset_peer: appPeersManager.getInputPeerByID(offsetPeerID),
offset_id: appMessagesIDsManager.getMessageLocalID(offsetID), offset_id: appMessagesIDsManager.getMessageLocalID(offsetID),
limit: limit || 20 limit: limit || 20
}, { }, {
@ -2396,7 +2445,7 @@ export class AppMessagesManager {
let pinnedIndex: number; let pinnedIndex: number;
if(dialog) { if(dialog) {
if(dialog.pinnedIndex) { if(dialog.hasOwnProperty('pinnedIndex')) {
pinnedIndex = dialog.pinnedIndex; pinnedIndex = dialog.pinnedIndex;
} else { } else {
dialog.pinnedIndex = pinnedIndex = this.pinnedIndex++; dialog.pinnedIndex = pinnedIndex = this.pinnedIndex++;
@ -2405,6 +2454,10 @@ export class AppMessagesManager {
pinnedIndex = this.pinnedIndex++; pinnedIndex = this.pinnedIndex++;
} }
if(pinnedIndex > this.pinnedIndex) {
this.pinnedIndex = pinnedIndex;
}
return 0x7fffff00 + (pinnedIndex & 0xff); return 0x7fffff00 + (pinnedIndex & 0xff);
} }
@ -2428,13 +2481,13 @@ export class AppMessagesManager {
delete this.newDialogsToHandle[peerID]; delete this.newDialogsToHandle[peerID];
} else { } else {
this.pushDialogToStorage(dialog); this.pushDialogToStorage(dialog);
if(!AppPeersManager.isChannel(+peerID)) { if(!appPeersManager.isChannel(+peerID)) {
newMaxSeenID = Math.max(newMaxSeenID, dialog.top_message || 0); newMaxSeenID = Math.max(newMaxSeenID, dialog.top_message || 0);
} }
} }
} }
console.log('after order:', this.dialogsStorage.dialogs[0].map(d => d.peerID)); //console.log('after order:', this.dialogsStorage[0].map(d => d.peerID));
if(newMaxSeenID != 0) { if(newMaxSeenID != 0) {
this.incrementMaxSeenID(newMaxSeenID); this.incrementMaxSeenID(newMaxSeenID);
@ -2452,7 +2505,7 @@ export class AppMessagesManager {
public readHistory(peerID: number, maxID = 0, minID = 0): Promise<boolean> { public readHistory(peerID: number, maxID = 0, minID = 0): Promise<boolean> {
// console.trace('start read') // console.trace('start read')
var isChannel = AppPeersManager.isChannel(peerID); var isChannel = appPeersManager.isChannel(peerID);
var historyStorage = this.historiesStorage[peerID]; var historyStorage = this.historiesStorage[peerID];
var foundDialog = this.getDialogByPeerID(peerID)[0]; var foundDialog = this.getDialogByPeerID(peerID)[0];
@ -2489,7 +2542,7 @@ export class AppMessagesManager {
}); });
} else { } else {
apiPromise = apiManager.invokeApi('messages.readHistory', { apiPromise = apiManager.invokeApi('messages.readHistory', {
peer: AppPeersManager.getInputPeerByID(peerID), peer: appPeersManager.getInputPeerByID(peerID),
max_id: maxID max_id: maxID
}).then((affectedMessages: any) => { }).then((affectedMessages: any) => {
apiUpdatesManager.processUpdateMessage({ apiUpdatesManager.processUpdateMessage({
@ -2539,9 +2592,6 @@ export class AppMessagesManager {
if(message && !message.pFlags.out) { if(message && !message.pFlags.out) {
message.pFlags.unread = false; message.pFlags.unread = false;
if(this.messagesForDialogs[messageID]) {
this.messagesForDialogs[messageID].pFlags.unread = false;
}
//NotificationsManager.cancel('msg' + messageID); // warning //NotificationsManager.cancel('msg' + messageID); // warning
} }
@ -2549,7 +2599,7 @@ export class AppMessagesManager {
} }
} }
// NotificationsManager.soundReset(AppPeersManager.getPeerString(peerID)) // warning // NotificationsManager.soundReset(appPeersManager.getPeerString(peerID)) // warning
return historyStorage.readPromise; return historyStorage.readPromise;
} }
@ -2602,7 +2652,7 @@ export class AppMessagesManager {
if(pendingData) { if(pendingData) {
var peerID: number = pendingData[0]; var peerID: number = pendingData[0];
var tempID = pendingData[1]; var tempID = pendingData[1];
var channelID = AppPeersManager.isChannel(peerID) ? -peerID : 0; var channelID = appPeersManager.isChannel(peerID) ? -peerID : 0;
var mid = appMessagesIDsManager.getFullMessageID(update.id, channelID); var mid = appMessagesIDsManager.getFullMessageID(update.id, channelID);
var message = this.messagesStorage[mid]; var message = this.messagesStorage[mid];
if(message) { if(message) {
@ -2721,7 +2771,7 @@ export class AppMessagesManager {
case 'updateDialogUnreadMark': { case 'updateDialogUnreadMark': {
console.log('updateDialogUnreadMark', update); console.log('updateDialogUnreadMark', update);
let peerID = AppPeersManager.getPeerID(update.peer.peer); let peerID = appPeersManager.getPeerID(update.peer.peer);
let foundDialog = this.getDialogByPeerID(peerID); let foundDialog = this.getDialogByPeerID(peerID);
if(!foundDialog.length) { if(!foundDialog.length) {
@ -2750,7 +2800,7 @@ export class AppMessagesManager {
peers.forEach((folderPeer: any) => { peers.forEach((folderPeer: any) => {
let {folder_id, peer} = folderPeer; let {folder_id, peer} = folderPeer;
let peerID = AppPeersManager.getPeerID(peer); let peerID = appPeersManager.getPeerID(peer);
let foundDialog = this.getDialogByPeerID(peerID); let foundDialog = this.getDialogByPeerID(peerID);
if(!foundDialog.length) { if(!foundDialog.length) {
this.newDialogsToHandle[peerID] = {reload: true}; this.newDialogsToHandle[peerID] = {reload: true};
@ -2758,7 +2808,7 @@ export class AppMessagesManager {
let dialog = foundDialog[0]; let dialog = foundDialog[0];
this.newDialogsToHandle[peerID] = dialog; this.newDialogsToHandle[peerID] = dialog;
this.dialogsStorage.dialogs[dialog.folder_id].splice(foundDialog[1], 1); this.dialogsStorage[dialog.folder_id].splice(foundDialog[1], 1);
dialog.folder_id = folder_id; dialog.folder_id = folder_id;
this.generateIndexForDialog(dialog); this.generateIndexForDialog(dialog);
@ -2770,7 +2820,7 @@ export class AppMessagesManager {
case 'updateDialogPinned': { case 'updateDialogPinned': {
console.log('updateDialogPinned', update); console.log('updateDialogPinned', update);
let peerID = AppPeersManager.getPeerID(update.peer.peer); let peerID = appPeersManager.getPeerID(update.peer.peer);
let foundDialog = this.getDialogByPeerID(peerID); let foundDialog = this.getDialogByPeerID(peerID);
this.scheduleHandleNewDialogs(); this.scheduleHandleNewDialogs();
@ -2806,7 +2856,7 @@ export class AppMessagesManager {
newPinned[dialog.peerID] = true; newPinned[dialog.peerID] = true;
}); });
this.dialogsStorage.dialogs[0].forEach((dialog: any) => { this.dialogsStorage[0].forEach((dialog: any) => {
let peerID = dialog.peerID; let peerID = dialog.peerID;
if(dialog.pFlags.pinned && !newPinned[peerID]) { if(dialog.pFlags.pinned && !newPinned[peerID]) {
this.newDialogsToHandle[peerID] = {reload: true}; this.newDialogsToHandle[peerID] = {reload: true};
@ -2817,13 +2867,13 @@ export class AppMessagesManager {
break; break;
} }
console.log('before order:', this.dialogsStorage.dialogs[0].map(d => d.peerID)); //console.log('before order:', this.dialogsStorage[0].map(d => d.peerID));
this.pinnedIndex = 0; this.pinnedIndex = 0;
let willHandle = false; let willHandle = false;
update.order.reverse(); // index must be higher update.order.reverse(); // index must be higher
update.order.forEach((peer: any) => { update.order.forEach((peer: any) => {
let peerID = AppPeersManager.getPeerID(peer.peer); let peerID = appPeersManager.getPeerID(peer.peer);
newPinned[peerID] = true; newPinned[peerID] = true;
let foundDialog = this.getDialogByPeerID(peerID); let foundDialog = this.getDialogByPeerID(peerID);
@ -2842,7 +2892,7 @@ export class AppMessagesManager {
willHandle = true; willHandle = true;
}); });
this.dialogsStorage.dialogs[0].forEach(dialog => { this.dialogsStorage[0].forEach(dialog => {
let peerID = dialog.peerID; let peerID = dialog.peerID;
if(dialog.pFlags.pinned && !newPinned[peerID]) { if(dialog.pFlags.pinned && !newPinned[peerID]) {
this.newDialogsToHandle[peerID] = {reload: true}; this.newDialogsToHandle[peerID] = {reload: true};
@ -2901,7 +2951,7 @@ export class AppMessagesManager {
var isOut = update._ == 'updateReadHistoryOutbox' || update._ == 'updateReadChannelOutbox'; var isOut = update._ == 'updateReadHistoryOutbox' || update._ == 'updateReadChannelOutbox';
var channelID: number = update.channel_id; var channelID: number = update.channel_id;
var maxID = appMessagesIDsManager.getFullMessageID(update.max_id, channelID); var maxID = appMessagesIDsManager.getFullMessageID(update.max_id, channelID);
var peerID = channelID ? -channelID : AppPeersManager.getPeerID(update.peer); var peerID = channelID ? -channelID : appPeersManager.getPeerID(update.peer);
var foundDialog = this.getDialogByPeerID(peerID); var foundDialog = this.getDialogByPeerID(peerID);
var history = (this.historiesStorage[peerID] || {}).history || []; var history = (this.historiesStorage[peerID] || {}).history || [];
var newUnreadCount = 0; var newUnreadCount = 0;
@ -2935,9 +2985,7 @@ export class AppMessagesManager {
if(!foundAffected) { if(!foundAffected) {
foundAffected = true; foundAffected = true;
} }
if(this.messagesForDialogs[messageID]) {
this.messagesForDialogs[messageID].pFlags.unread = false;
}
if(!message.pFlags.out) { if(!message.pFlags.out) {
if(foundDialog[0]) { if(foundDialog[0]) {
newUnreadCount = --foundDialog[0].unread_count; newUnreadCount = --foundDialog[0].unread_count;
@ -3007,33 +3055,22 @@ export class AppMessagesManager {
case 'updateDeleteMessages': case 'updateDeleteMessages':
case 'updateDeleteChannelMessages': { case 'updateDeleteChannelMessages': {
var historiesUpdated: any = {}; let historiesUpdated: {[peerID: number]: {count: number, unread: number, msgs: {[mid: number]: true}}} = {};
var channelID: number = update.channel_id; let channelID: number = update.channel_id;
var messageID: number;
var message, i; for(let i = 0; i < update.messages.length; i++) {
var peerID: number, foundDialog: ReturnType<AppMessagesManager['getDialogByPeerID']>; let messageID = appMessagesIDsManager.getFullMessageID(update.messages[i], channelID);
let history: any; let message = this.messagesStorage[messageID];
var peerMessagesToHandle;
var peerMessagesHandlePos;
for (i = 0; i < update.messages.length; i++) {
messageID = appMessagesIDsManager.getFullMessageID(update.messages[i], channelID);
message = this.messagesStorage[messageID];
if(message) { if(message) {
peerID = this.getMessagePeer(message); let peerID = this.getMessagePeer(message);
history = historiesUpdated[peerID] || (historiesUpdated[peerID] = {count: 0, unread: 0, msgs: {}}); let history = historiesUpdated[peerID] || (historiesUpdated[peerID] = {count: 0, unread: 0, msgs: {}});
if(!message.pFlags.out && message.pFlags.unread) { if(!message.pFlags.out && message.pFlags.unread) {
history.unread++; history.unread++;
// NotificationsManager.cancel('msg' + messageID); // warning
} }
history.count++; history.count++;
history.msgs[messageID] = true; history.msgs[messageID] = true;
if(this.messagesForDialogs[messageID]) {
this.messagesForDialogs[messageID].deleted = true;
delete this.messagesForDialogs[messageID];
}
message.deleted = true message.deleted = true
this.messagesStorage[messageID] = { this.messagesStorage[messageID] = {
deleted: true, deleted: true,
@ -3045,9 +3082,9 @@ export class AppMessagesManager {
date: message.date date: message.date
}; };
peerMessagesToHandle = this.newMessagesToHandle[peerID]; let peerMessagesToHandle = this.newMessagesToHandle[peerID];
if(peerMessagesToHandle && peerMessagesToHandle.length) { if(peerMessagesToHandle && peerMessagesToHandle.length) {
peerMessagesHandlePos = peerMessagesToHandle.indexOf(messageID); let peerMessagesHandlePos = peerMessagesToHandle.indexOf(messageID);
if(peerMessagesHandlePos != -1) { if(peerMessagesHandlePos != -1) {
peerMessagesToHandle.splice(peerMessagesHandlePos); peerMessagesToHandle.splice(peerMessagesHandlePos);
} }
@ -3055,13 +3092,13 @@ export class AppMessagesManager {
} }
} }
Object.keys(historiesUpdated).forEach((peerID: string) => { Object.keys(historiesUpdated).forEach(peerID => {
let updatedData = historiesUpdated[peerID]; let updatedData = historiesUpdated[+peerID];
var historyStorage = this.historiesStorage[peerID]; let historyStorage = this.historiesStorage[peerID];
if(historyStorage !== undefined) { if(historyStorage !== undefined) {
var newHistory = [] let newHistory: number[] = [];
var newPending = [] let newPending: number[] = [];
for(var i = 0; i < historyStorage.history.length; i++) { for(let i = 0; i < historyStorage.history.length; i++) {
if(!updatedData.msgs[historyStorage.history[i]]) { if(!updatedData.msgs[historyStorage.history[i]]) {
newHistory.push(historyStorage.history[i]); newHistory.push(historyStorage.history[i]);
} }
@ -3070,13 +3107,13 @@ export class AppMessagesManager {
if(updatedData.count && if(updatedData.count &&
historyStorage.count !== null && historyStorage.count !== null &&
historyStorage.count > 0) { historyStorage.count > 0) {
historyStorage.count -= updatedData.count historyStorage.count -= updatedData.count;
if(historyStorage.count < 0) { if(historyStorage.count < 0) {
historyStorage.count = 0; historyStorage.count = 0;
} }
} }
for(var i = 0; i < historyStorage.pending.length; i++) { for(let i = 0; i < historyStorage.pending.length; i++) {
if(!updatedData.msgs[historyStorage.pending[i]]) { if(!updatedData.msgs[historyStorage.pending[i]]) {
newPending.push(historyStorage.pending[i]); newPending.push(historyStorage.pending[i]);
} }
@ -3086,7 +3123,7 @@ export class AppMessagesManager {
$rootScope.$broadcast('history_delete', {peerID: peerID, msgs: updatedData.msgs}); $rootScope.$broadcast('history_delete', {peerID: peerID, msgs: updatedData.msgs});
} }
var foundDialog = this.getDialogByPeerID(+peerID)[0]; let foundDialog = this.getDialogByPeerID(+peerID)[0];
if(foundDialog) { if(foundDialog) {
if(updatedData.unread) { if(updatedData.unread) {
foundDialog.unread_count -= updatedData.unread; foundDialog.unread_count -= updatedData.unread;
@ -3101,7 +3138,7 @@ export class AppMessagesManager {
this.reloadConversation(+peerID); this.reloadConversation(+peerID);
} }
} }
}) });
break; break;
} }
@ -3127,7 +3164,7 @@ export class AppMessagesManager {
this.reloadConversation(-channelID); this.reloadConversation(-channelID);
} else { } else {
if(foundDialog[0]) { if(foundDialog[0]) {
this.dialogsStorage.dialogs[foundDialog[0].folder_id].splice(foundDialog[1], 1); this.dialogsStorage[foundDialog[0].folder_id].splice(foundDialog[1], 1);
$rootScope.$broadcast('dialog_drop', {peerID: peerID, dialog: foundDialog[0]}); $rootScope.$broadcast('dialog_drop', {peerID: peerID, dialog: foundDialog[0]});
} }
} }
@ -3141,7 +3178,7 @@ export class AppMessagesManager {
let peerID = -channelID; let peerID = -channelID;
let foundDialog = this.getDialogByPeerID(peerID); let foundDialog = this.getDialogByPeerID(peerID);
if(foundDialog[0]) { if(foundDialog[0]) {
this.dialogsStorage.dialogs[foundDialog[0].folder_id].splice(foundDialog[1], 1); this.dialogsStorage[foundDialog[0].folder_id].splice(foundDialog[1], 1);
} }
delete this.historiesStorage[peerID]; delete this.historiesStorage[peerID];
@ -3167,8 +3204,6 @@ export class AppMessagesManager {
} }
case 'updateServiceNotification': { case 'updateServiceNotification': {
// update.inbox_date = tsNow(true)
// update.pFlags = {popup: true}
var fromID = 777000; var fromID = 777000;
var peerID = fromID; var peerID = fromID;
var messageID = this.tempID--; var messageID = this.tempID--;
@ -3176,7 +3211,7 @@ export class AppMessagesManager {
_: 'message', _: 'message',
id: messageID, id: messageID,
from_id: fromID, from_id: fromID,
to_id: AppPeersManager.getOutputPeer(peerID), to_id: appPeersManager.getOutputPeer(peerID),
flags: 0, flags: 0,
pFlags: {unread: true}, pFlags: {unread: true},
date: (update.inbox_date || tsNow(true)) + serverTimeManager.serverTimeOffset, date: (update.inbox_date || tsNow(true)) + serverTimeManager.serverTimeOffset,
@ -3203,9 +3238,7 @@ export class AppMessagesManager {
message: message message: message
}); });
} }
if(update.pFlags.popup && update.message) {
//ErrorService.show({error: {code: 400, type: 'UPDATE_SERVICE_NOTIFICATION'}, historyMessage: historyMessage}); // warning
}
break; break;
} }
} }
@ -3464,14 +3497,14 @@ export class AppMessagesManager {
} }
public requestHistory(peerID: number, maxID: number, limit: number, offset = 0): Promise<any> { public requestHistory(peerID: number, maxID: number, limit: number, offset = 0): Promise<any> {
var isChannel = AppPeersManager.isChannel(peerID); var isChannel = appPeersManager.isChannel(peerID);
//console.trace('requestHistory', peerID, maxID, limit, offset); //console.trace('requestHistory', peerID, maxID, limit, offset);
$rootScope.$broadcast('history_request'); $rootScope.$broadcast('history_request');
return apiManager.invokeApi('messages.getHistory', { return apiManager.invokeApi('messages.getHistory', {
peer: AppPeersManager.getInputPeerByID(peerID), peer: appPeersManager.getInputPeerByID(peerID),
offset_id: maxID ? appMessagesIDsManager.getMessageLocalID(maxID) : 0, offset_id: maxID ? appMessagesIDsManager.getMessageLocalID(maxID) : 0,
offset_date: 0, offset_date: 0,
add_offset: offset || 0, add_offset: offset || 0,
@ -3523,7 +3556,7 @@ export class AppMessagesManager {
_: 'messageService', _: 'messageService',
id: messageID, id: messageID,
from_id: peerID, from_id: peerID,
to_id: AppPeersManager.getOutputPeer(peerID), to_id: appPeersManager.getOutputPeer(peerID),
flags: 0, flags: 0,
pFlags: {}, pFlags: {},
date: tsNow(true) + serverTimeManager.serverTimeOffset, date: tsNow(true) + serverTimeManager.serverTimeOffset,
@ -3617,16 +3650,14 @@ export class AppMessagesManager {
public wrapSingleMessage(msgID: number) { public wrapSingleMessage(msgID: number) {
if(this.messagesStorage[msgID]) { if(this.messagesStorage[msgID]) {
//let ret = this.wrapForDialog(msgID); // hm
$rootScope.$broadcast('messages_downloaded', [msgID]); $rootScope.$broadcast('messages_downloaded', [msgID]);
//return ret;
return {mid: msgID, loading: false}; return {mid: msgID, loading: false};
} }
if(this.needSingleMessages.indexOf(msgID) == -1) { if(this.needSingleMessages.indexOf(msgID) == -1) {
this.needSingleMessages.push(msgID); this.needSingleMessages.push(msgID);
if(this.fetchSingleMessagesTimeout == 0) { if(this.fetchSingleMessagesTimeout == 0) {
this.fetchSingleMessagesTimeout = window.setTimeout(this.fetchSingleMessages.bind(this), 25); this.fetchSingleMessagesTimeout = window.setTimeout(this.fetchSingleMessages.bind(this), 10);
} }
return {mid: msgID, loading: true}; return {mid: msgID, loading: true};

29
src/lib/appManagers/appPhotosManager.ts

@ -184,34 +184,47 @@ export class AppPhotosManager {
arr[164] = bytes[1]; arr[164] = bytes[1];
arr[166] = bytes[2]; arr[166] = bytes[2];
} else { } else {
arr = bytes; arr = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
} }
//console.log('setAttachmentPreview', bytes, arr, div, isSticker); //console.log('setAttachmentPreview', bytes, arr, div, isSticker);
let blob = new Blob([arr], {type: "image/jpeg"}); let blob = new Blob([arr], {type: "image/jpeg"});
/* let reader = new FileReader();
reader.onloadend = () => {
let src = reader.result;
};
reader.readAsDataURL(blob); */
if(background) { if(background) {
let url = URL.createObjectURL(blob); let url = URL.createObjectURL(blob);
let img = new Image(); let img = new Image();
img.src = url; img.src = url;
img.onload = () => { img.addEventListener('load', () => {
element.style.backgroundImage = 'url(' + url + ')'; element.style.backgroundImage = 'url(' + url + ')';
}; });
return element;
//element.style.backgroundImage = 'url(' + url + ')'; //element.style.backgroundImage = 'url(' + url + ')';
} else { } else {
if(element instanceof SVGSVGElement) { if(element instanceof SVGSVGElement) {
let image = element.firstElementChild as SVGImageElement || document.createElementNS("http://www.w3.org/2000/svg", "image"); let image = element.firstElementChild as SVGImageElement || document.createElementNS("http://www.w3.org/2000/svg", "image");
image.setAttributeNS(null, 'href', URL.createObjectURL(blob)); image.setAttributeNS(null, 'href', URL.createObjectURL(blob));
element.append(image); element.append(image);
return image;
} else if(element instanceof HTMLImageElement) {
element.src = URL.createObjectURL(blob);
return element;
} else { } else {
let image = new Image(); let img = new Image();
image.src = URL.createObjectURL(blob); img.style.width = '100%';
img.style.height = '100%';
image.style.width = '100%'; img.src = URL.createObjectURL(blob);
image.style.height = '100%'; element.append(img);
element.append(image); return img;
} }
} }
} }

231
src/lib/appManagers/appSidebarRight.ts

@ -1,4 +1,4 @@
import { horizontalMenu, formatPhoneNumber, putPreloader, renderImageFromUrl } from "../../components/misc"; import { horizontalMenu, putPreloader, renderImageFromUrl } from "../../components/misc";
//import Scrollable from '../../components/scrollable'; //import Scrollable from '../../components/scrollable';
import Scrollable from '../../components/scrollable_new'; import Scrollable from '../../components/scrollable_new';
import { $rootScope } from "../utils"; import { $rootScope } from "../utils";
@ -18,6 +18,22 @@ import AvatarElement from "../../components/avatar";
const testScroll = false; const testScroll = false;
let setText = (text: string, el: HTMLDivElement) => {
window.requestAnimationFrame(() => {
if(el.childElementCount > 1) {
el.firstElementChild.remove();
}
let p = document.createElement('p');
p.innerHTML = text;
el.prepend(p);
el.style.display = '';
//this.scroll.getScrollTopOffset();
});
};
class AppSidebarRight { class AppSidebarRight {
public sidebarEl = document.getElementById('column-right') as HTMLDivElement; public sidebarEl = document.getElementById('column-right') as HTMLDivElement;
public profileContainer = this.sidebarEl.querySelector('.profile-container') as HTMLDivElement; public profileContainer = this.sidebarEl.querySelector('.profile-container') as HTMLDivElement;
@ -56,7 +72,7 @@ class AppSidebarRight {
'inputMessagesFilterUrl', 'inputMessagesFilterUrl',
'inputMessagesFilterMusic' 'inputMessagesFilterMusic'
]; ];
public sharedMediaType: string = ''; public sharedMediaType: AppSidebarRight['sharedMediaTypes'][number] = '';
private sharedMediaSelected: HTMLDivElement = null; private sharedMediaSelected: HTMLDivElement = null;
private lazyLoadQueueSidebar = new LazyLoadQueue(5); private lazyLoadQueueSidebar = new LazyLoadQueue(5);
@ -91,6 +107,8 @@ class AppSidebarRight {
public privateSearch = new AppSearch(this.searchContainer.querySelector('.chats-container') as HTMLDivElement, this.searchInput, { public privateSearch = new AppSearch(this.searchContainer.querySelector('.chats-container') as HTMLDivElement, this.searchInput, {
messages: new SearchGroup('Private Search', 'messages') messages: new SearchGroup('Private Search', 'messages')
}); });
private loadMutex: Promise<any> = Promise.resolve();
constructor() { constructor() {
let container = this.profileContentEl.querySelector('.content-container .tabs-container') as HTMLDivElement; let container = this.profileContentEl.querySelector('.content-container .tabs-container') as HTMLDivElement;
@ -156,7 +174,7 @@ class AppSidebarRight {
let ids = Object.keys(this.mediaDivsByIDs).map(k => +k).sort((a, b) => a - b); let ids = Object.keys(this.mediaDivsByIDs).map(k => +k).sort((a, b) => a - b);
let idx = ids.findIndex(i => i == messageID); let idx = ids.findIndex(i => i == messageID);
let targets = ids.map(id => ({element: this.mediaDivsByIDs[id], mid: id})); let targets = ids.map(id => ({element: this.mediaDivsByIDs[id].firstElementChild as HTMLElement, mid: id}));
appMediaViewer.openMedia(message, target, false, this.sidebarEl, targets.slice(idx + 1).reverse(), targets.slice(0, idx).reverse(), true); appMediaViewer.openMedia(message, target, false, this.sidebarEl, targets.slice(idx + 1).reverse(), targets.slice(0, idx).reverse(), true);
}); });
@ -289,12 +307,11 @@ class AppSidebarRight {
return filtered; return filtered;
} }
public performSearchResult(messages: any[], type: string) { public async performSearchResult(messages: any[], type: string) {
let peerID = this.peerID; let peerID = this.peerID;
let sharedMediaDiv: HTMLDivElement; let sharedMediaDiv: HTMLDivElement;
let elemsToAppend: HTMLElement[] = []; let elemsToAppend: HTMLElement[] = [];
let promises: Promise<any>[] = [];
// https://core.telegram.org/type/MessagesFilter // https://core.telegram.org/type/MessagesFilter
switch(type) { switch(type) {
@ -305,22 +322,23 @@ class AppSidebarRight {
let media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document); let media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);
let div = document.createElement('div'); let div = document.createElement('div');
div.classList.add('media-item');
//console.log(message, photo); //console.log(message, photo);
let isPhoto = media._ == 'photo'; let isPhoto = media._ == 'photo';
let photo = isPhoto ? appPhotosManager.getPhoto(media.id) : null; let photo = isPhoto ? appPhotosManager.getPhoto(media.id) : null;
let isDownloaded = (photo && photo.downloaded) || appPhotosManager.getDocumentCachedThumb(media.id); let isDownloaded: boolean;
if(!isDownloaded) { if(photo) {
//this.log('inputMessagesFilterPhotoVideo', message, media, photo, div); isDownloaded = photo.downloaded > 0;
} else {
let sizes = media.sizes || media.thumbs; let cachedThumb = appPhotosManager.getDocumentCachedThumb(media.id);
if(sizes && sizes[0].bytes) { isDownloaded = cachedThumb?.downloaded > 0;
appPhotosManager.setAttachmentPreview(sizes[0].bytes, div, false, true);
} /* else {
this.log('no stripped size', message, media);
} */
} }
let img = new Image();
img.classList.add('media-image');
div.append(img);
//this.log('inputMessagesFilterPhotoVideo', message, media); //this.log('inputMessagesFilterPhotoVideo', message, media);
@ -349,14 +367,37 @@ class AppSidebarRight {
let url = (photo && photo.url) || appPhotosManager.getDocumentCachedThumb(media.id).url; let url = (photo && photo.url) || appPhotosManager.getDocumentCachedThumb(media.id).url;
if(url) { if(url) {
renderImageFromUrl(div, url); renderImageFromUrl(img, url);
} }
}); });
div.dataset.mid = '' + message.mid; img.dataset.mid = '' + message.mid;
let sizes = media.sizes || media.thumbs;
if(isDownloaded || (sizes && sizes[0].bytes)) {
let promise = new Promise((resolve, reject) => {
img.addEventListener('load', () => {
clearTimeout(timeout);
resolve();
});
let timeout = setTimeout(() => {
this.log('did not loaded', img, media, isDownloaded, sizes);
reject();
}, 1e3);
});
promises.push(promise);
}
if(isDownloaded) load(); if(isDownloaded) load();
else this.lazyLoadQueueSidebar.push({div, load}); else {
if(sizes && sizes[0].bytes) {
appPhotosManager.setAttachmentPreview(sizes[0].bytes, img, false, false);
}
this.lazyLoadQueueSidebar.push({div, load});
}
this.lastSharedMediaDiv.append(div); this.lastSharedMediaDiv.append(div);
if(this.lastSharedMediaDiv.childElementCount == 3) { if(this.lastSharedMediaDiv.childElementCount == 3) {
@ -365,6 +406,7 @@ class AppSidebarRight {
} }
this.lastSharedMediaDiv = document.createElement('div'); this.lastSharedMediaDiv = document.createElement('div');
this.lastSharedMediaDiv.classList.add('media-row');
} }
this.mediaDivsByIDs[message.mid] = div; this.mediaDivsByIDs[message.mid] = div;
@ -397,6 +439,8 @@ class AppSidebarRight {
//this.log('wrapping webpage', webpage); //this.log('wrapping webpage', webpage);
previewDiv.innerText = (webpage.title || webpage.description || webpage.url || webpage.display_url).slice(0, 1);
previewDiv.classList.add('empty');
if(webpage.photo) { if(webpage.photo) {
let load = () => appPhotosManager.preloadPhoto(webpage.photo.id, appPhotosManager.choosePhotoSize(webpage.photo, 60, 60)) let load = () => appPhotosManager.preloadPhoto(webpage.photo.id, appPhotosManager.choosePhotoSize(webpage.photo, 60, 60))
.then(() => { .then(() => {
@ -405,13 +449,12 @@ class AppSidebarRight {
return; return;
} }
previewDiv.classList.remove('empty');
renderImageFromUrl(previewDiv, webpage.photo.url); renderImageFromUrl(previewDiv, webpage.photo.url);
}); });
this.lazyLoadQueueSidebar.push({div: previewDiv, load}); this.lazyLoadQueueSidebar.push({div: previewDiv, load});
} else {
previewDiv.innerText = (webpage.title || webpage.description || webpage.url || webpage.display_url).slice(0, 1);
previewDiv.classList.add('empty');
} }
let title = webpage.rTitle || ''; let title = webpage.rTitle || '';
@ -457,11 +500,19 @@ class AppSidebarRight {
if(this.lastSharedMediaDiv.childElementCount && !this.scroll.contains(this.lastSharedMediaDiv)) { if(this.lastSharedMediaDiv.childElementCount && !this.scroll.contains(this.lastSharedMediaDiv)) {
elemsToAppend.push(this.lastSharedMediaDiv); elemsToAppend.push(this.lastSharedMediaDiv);
} }
if(this.loadMutex) {
promises.push(this.loadMutex);
}
if(elemsToAppend.length) { if(elemsToAppend.length) {
//window.requestAnimationFrame(() => { if(promises.length) {
//elemsToAppend.forEach(el => this.scroll.append(el, false)); await Promise.all(promises);
//}); if(this.peerID != peerID) {
this.log.warn('peer changed');
return;
}
}
sharedMediaDiv.append(...elemsToAppend); sharedMediaDiv.append(...elemsToAppend);
} }
@ -521,7 +572,7 @@ class AppSidebarRight {
this.usedFromHistory[type] = used; this.usedFromHistory[type] = used;
if(messages.length) { if(messages.length) {
this.performSearchResult(messages, type); return this.performSearchResult(messages, type);
} }
return Promise.resolve(); return Promise.resolve();
@ -556,7 +607,7 @@ class AppSidebarRight {
this.usedFromHistory[type] = history.length; this.usedFromHistory[type] = history.length;
if(ids.length) { if(ids.length) {
this.performSearchResult(this.filterMessagesByType(ids, type), type); return this.performSearchResult(this.filterMessagesByType(ids, type), type);
} }
}, (err) => { }, (err) => {
this.log.error('load error:', err); this.log.error('load error:', err);
@ -567,77 +618,77 @@ class AppSidebarRight {
return Promise.all(promises); return Promise.all(promises);
} }
public fillProfileElements() { public cleanup() {
let peerID = this.peerID = $rootScope.selectedPeerID;
this.loadSidebarMediaPromises = {}; this.loadSidebarMediaPromises = {};
this.loadedAllMedia = {}; this.loadedAllMedia = {};
this.lastSharedMediaDiv = document.createElement('div'); this.lastSharedMediaDiv = document.createElement('div');
this.lastSharedMediaDiv.classList.add('media-row');
this.prevTabID = -1;
this.scroll.setVirtualContainer(null);
this.mediaDivsByIDs = {};
//this.log('fillProfileElements'); this.lazyLoadQueueSidebar.clear();
this.sharedMediaTypes.forEach(type => {
this.usedFromHistory[type] = 0;
});
this.sharedMediaType = 'inputMessagesFilterPhotoVideo';
}
public cleanupHTML() {
this.contentContainer.classList.remove('loaded'); this.contentContainer.classList.remove('loaded');
this.profileElements.avatar.setAttribute('peer', '' + peerID); this.profileContentEl.parentElement.scrollTop = 0;
this.profileElements.bio.style.display = 'none';
window.requestAnimationFrame(() => { this.profileElements.phone.style.display = 'none';
this.profileContentEl.parentElement.scrollTop = 0; this.profileElements.username.style.display = 'none';
this.profileElements.bio.style.display = 'none'; this.profileElements.notificationsRow.style.display = '';
this.profileElements.phone.style.display = 'none'; this.profileElements.notificationsCheckbox.checked = true;
this.profileElements.username.style.display = 'none'; this.profileElements.notificationsStatus.innerText = 'Enabled';
this.profileElements.notificationsRow.style.display = '';
this.profileElements.notificationsCheckbox.checked = true; if(this.urlsToRevoke.length) {
this.profileElements.notificationsStatus.innerText = 'Enabled'; this.urlsToRevoke.forEach(url => {
URL.revokeObjectURL(url);
});
this.urlsToRevoke.length = 0;
}
Object.keys(this.sharedMedia).forEach(key => {
this.sharedMedia[key].innerHTML = '';
Object.keys(this.sharedMedia).forEach(key => { if(!this.historiesStorage[this.peerID] || !this.historiesStorage[this.peerID][key]) {
this.sharedMedia[key].innerHTML = '';
let parent = this.sharedMedia[key].parentElement; let parent = this.sharedMedia[key].parentElement;
if(!parent.querySelector('.preloader')) { if(!parent.querySelector('.preloader')) {
putPreloader(parent, true); putPreloader(parent, true);
} }
}); }
this.prevTabID = -1;
this.scroll.setVirtualContainer(null);
(this.profileTabs.firstElementChild.children[1] as HTMLLIElement).click(); // set media
//this.scroll.getScrollTopOffset();
this.loadSidebarMedia(true);
});
this.mediaDivsByIDs = {};
this.lazyLoadQueueSidebar.clear();
this.urlsToRevoke.forEach(url => {
URL.revokeObjectURL(url);
});
this.urlsToRevoke.length = 0;
this.sharedMediaTypes.forEach(type => {
this.usedFromHistory[type] = 0;
}); });
let setText = (text: string, el: HTMLDivElement) => {
window.requestAnimationFrame(() => {
if(el.childElementCount > 1) {
el.firstElementChild.remove();
}
let p = document.createElement('p');
p.innerHTML = text;
el.prepend(p);
el.style.display = '';
//this.scroll.getScrollTopOffset(); (this.profileTabs.firstElementChild.children[1] as HTMLLIElement).click(); // set media
}); }
};
public setLoadMutex(promise: Promise<any>) {
this.loadMutex = promise;
}
public setPeer(peerID: number) {
this.peerID = peerID;
this.cleanup();
}
public fillProfileElements() {
let peerID = this.peerID = $rootScope.selectedPeerID;
this.cleanupHTML();
this.profileElements.avatar.setAttribute('peer', '' + peerID);
// username // username
if(peerID != appImManager.myID) { if(peerID != $rootScope.myID) {
let username = appPeersManager.getPeerUsername(peerID); let username = appPeersManager.getPeerUsername(peerID);
if(username) { if(username) {
setText(appPeersManager.getPeerUsername(peerID), this.profileElements.username); setText(appPeersManager.getPeerUsername(peerID), this.profileElements.username);
@ -656,13 +707,12 @@ class AppSidebarRight {
} else { } else {
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
this.profileElements.notificationsRow.style.display = 'none'; this.profileElements.notificationsRow.style.display = 'none';
//this.scroll.getScrollTopOffset(); });
})
} }
if(peerID > 0) { if(peerID > 0) {
let user = appUsersManager.getUser(peerID); let user = appUsersManager.getUser(peerID);
if(user.phone && peerID != appImManager.myID) { if(user.phone && peerID != $rootScope.myID) {
setText(user.rPhone, this.profileElements.phone); setText(user.rPhone, this.profileElements.phone);
} }
@ -672,7 +722,7 @@ class AppSidebarRight {
return; return;
} }
if(userFull.rAbout && peerID != appImManager.myID) { if(userFull.rAbout && peerID != $rootScope.myID) {
setText(userFull.rAbout, this.profileElements.bio); setText(userFull.rAbout, this.profileElements.bio);
} }
@ -682,8 +732,6 @@ class AppSidebarRight {
appImManager.pinnedMsgID = userFull.pinned_msg_id; appImManager.pinnedMsgID = userFull.pinned_msg_id;
appMessagesManager.wrapSingleMessage(userFull.pinned_msg_id); appMessagesManager.wrapSingleMessage(userFull.pinned_msg_id);
} }
//this.scroll.getScrollTopOffset();
}); });
} else { } else {
let chat = appPeersManager.getPeer(peerID); let chat = appPeersManager.getPeer(peerID);
@ -699,13 +747,8 @@ class AppSidebarRight {
if(chatFull.about) { if(chatFull.about) {
setText(RichTextProcessor.wrapRichText(chatFull.about), this.profileElements.bio); setText(RichTextProcessor.wrapRichText(chatFull.about), this.profileElements.bio);
} }
//this.scroll.getScrollTopOffset();
}); });
} }
//this.scroll.getScrollTopOffset();
//this.loadSidebarMedia();
} }
} }

10
src/lib/appManagers/appStickersManager.ts

@ -60,9 +60,6 @@ class AppStickersManager {
for(let id in sets) { for(let id in sets) {
let set = sets[id]; let set = sets[id];
set.documents.forEach(doc => { set.documents.forEach(doc => {
delete doc.downloaded;
delete doc.url;
this.saveSticker(doc); this.saveSticker(doc);
}); });
} }
@ -78,13 +75,6 @@ class AppStickersManager {
public saveSticker(doc: MTDocument) { public saveSticker(doc: MTDocument) {
if(this.documents[doc.id]) return this.documents[doc.id]; if(this.documents[doc.id]) return this.documents[doc.id];
/* Object.keys(doc).forEach(key => {
if(doc[key] instanceof Uint8Array) {
doc[key] = Array.from(doc[key]);
}
}); */
doc.file_reference = Array.from(doc.file_reference);
doc = appDocsManager.saveDoc(doc); doc = appDocsManager.saveDoc(doc);
this.documents[doc.id] = doc; this.documents[doc.id] = doc;

2
src/lib/appManagers/appUsersManager.ts

@ -228,7 +228,7 @@ export class AppUsersManager {
var nameWords = apiUser.sortName.split(' '); var nameWords = apiUser.sortName.split(' ');
var firstWord = nameWords.shift(); var firstWord = nameWords.shift();
var lastWord = nameWords.pop(); var lastWord = nameWords.pop();
apiUser.initials = firstWord.charAt(0) + (lastWord ? lastWord.charAt(0) : firstWord.charAt(1)); apiUser.initials = firstWord.charAt(0) + (lastWord ? lastWord.charAt(0) : '');
if(apiUser.status) { if(apiUser.status) {
if(apiUser.status.expires) { if(apiUser.status.expires) {

7
src/lib/polyfill.ts

@ -84,6 +84,10 @@ Uint8Array.prototype.toString = function() {
return String.fromCharCode.apply(null, [...this]); return String.fromCharCode.apply(null, [...this]);
}; };
Uint8Array.prototype.toJSON = function() {
return [...this];
};
Array.prototype.forEachReverse = function<T>(callback: (value: T, index?: number, array?: Array<T>) => void) { Array.prototype.forEachReverse = function<T>(callback: (value: T, index?: number, array?: Array<T>) => void) {
let length = this.length; let length = this.length;
for(var i = length - 1; i >= 0; --i) { for(var i = length - 1; i >= 0; --i) {
@ -113,7 +117,8 @@ declare global {
hex: string; hex: string;
randomize: () => Uint8Array, randomize: () => Uint8Array,
concat: (...args: Array<Uint8Array | ArrayBuffer | number[]>) => Uint8Array, concat: (...args: Array<Uint8Array | ArrayBuffer | number[]>) => Uint8Array,
toString: () => string toString: () => string,
toJSON: () => number[],
} }
interface Array<T> { interface Array<T> {

7
src/lib/storage.ts

@ -67,8 +67,11 @@ class ConfigStorage {
value = obj[key]; value = obj[key];
key = prefix + key; key = prefix + key;
this.cache[key] = value; this.cache[key] = value;
//value = value instanceof Uint8Array ? Array.from(value) : JSON.stringify(value); value = JSON.stringify(value, (key, value) => {
value = JSON.stringify(value); if(key == 'downloaded' || (key == 'url' && value.indexOf('blob:') === 0)) return undefined;
return value;
});
if(this.useLs) { if(this.useLs) {
try { try {
//console.log('setItem', key, value); //console.log('setItem', key, value);

5
src/lib/utils.js

@ -754,7 +754,8 @@ function versionCompare (ver1, ver2) {
} }
var badCharsRe = /[`~!@#$%^&*()\-_=+\[\]\\|{}'";:\/?.>,<\s]+/g, //var badCharsRe = /[`~!@#$%^&*()\-_=+\[\]\\|{}'";:\/?.>,<\s]+/g,
var badCharsRe = /[`~!@#$%^&*()\-_=+\[\]\\|{}'";:\/?.>,<]+/g,
trimRe = /^\s+|\s$/g trimRe = /^\s+|\s$/g
function createIndex () { function createIndex () {
@ -766,7 +767,7 @@ function versionCompare (ver1, ver2) {
function cleanSearchText(text, latinize = true) { function cleanSearchText(text, latinize = true) {
var hasTag = text.charAt(0) == '%'; var hasTag = text.charAt(0) == '%';
text = text.replace(badCharsRe, ' ').replace(trimRe, ''); text = text.replace(badCharsRe, '').replace(trimRe, '');
if(latinize) { if(latinize) {
text = text.replace(/[^A-Za-z0-9]/g, (ch) => { text = text.replace(/[^A-Za-z0-9]/g, (ch) => {
var latinizeCh = Config.LatinizeMap[ch]; var latinizeCh = Config.LatinizeMap[ch];

107
src/scss/partials/_chatBubble.scss

@ -14,36 +14,52 @@
.bubble { .bubble {
padding-top: 5px; padding-top: 5px;
/* display: grid;
grid-template-columns: 1fr $chat-max-width 1fr;
grid-row-gap: 0px; */
max-width: $chat-max-width; max-width: $chat-max-width;
margin: 0 auto; margin: 0 auto;
position: relative; position: relative;
&.is-selected { &.is-selected {
&:before { &:after {
position: absolute; position: absolute;
width: 200%;
height: 100%;
background-color: rgba(0, 132, 255, .3);
content: " ";
display: block;
left: -50%; left: -50%;
top: 0; top: 0;
height: 100%;
content: " ";
background-color: rgba(0, 132, 255, .3);
animation: bubbleSelected 2s linear; animation: bubbleSelected 2s linear;
z-index: 1;
} }
&:not(.is-group-last):before { &:not(.is-group-last):after {
height: calc(100% + 5px); height: calc(100% + 5px);
} }
} }
&.is-first-unread {
&:before {
content: "Unread messages";
height: 30px;
margin-bottom: 5px;
margin-left: -50%;
text-align: center;
color: #538BCC;
line-height: 2.1;
font-weight: 500;
font-size: 15px;
background-color: rgba(255, 255, 255, 0.95);
}
}
&.is-selected:after, &.is-first-unread:before {
width: 200%;
display: block;
}
&.is-date { &.is-date {
position: -webkit-sticky; position: -webkit-sticky;
position: sticky; position: sticky;
top: 5px; top: 5px;
z-index: 2; z-index: 3;
pointer-events: none; pointer-events: none;
&.is-sticky { &.is-sticky {
@ -53,11 +69,6 @@
} }
} }
/* &:before, &:after {
content: " ";
width: 100%;
} */
&__container { &__container {
//min-width: 60px; //min-width: 60px;
min-width: 56px; min-width: 56px;
@ -70,6 +81,7 @@
/* font-size: 0; */ /* font-size: 0; */
width: max-content; width: max-content;
height: fit-content; height: fit-content;
z-index: 2;
> .user-avatar { > .user-avatar {
position: absolute; position: absolute;
@ -560,6 +572,14 @@
.emoji { .emoji {
font-size: 1.2rem; font-size: 1.2rem;
} }
pre, code {
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
} }
// all for audio (not voice) // all for audio (not voice)
@ -1204,7 +1224,62 @@
} }
} }
.reply-markup {
position: absolute;
width: 100%;
&-row {
margin-top: 5px;
overflow: hidden;
height: 40px;
display: flex;
&:last-child {
border-bottom-left-radius: $border-radius-big;
border-bottom-right-radius: $border-radius-big;
}
}
&-button {
display: flex;
justify-content: center;
align-items: center;
border-radius: 6px;
background-color: rgba(0, 0, 0, 0.23);
z-index: 2;
font-size: 14px;
user-select: none;
text-align: center;
color: white !important;
outline: none;
border: none;
width: 100%;
cursor: pointer;
position: relative;
transition: background-color 0.35s ease;
&:hover {
background-color: rgba(0, 0, 0, 0.06);
}
& + & {
margin-left: 5px;
}
&.is-link:before {
content: $tgico-next;
position: absolute;
right: 2px;
top: 2px;
display: block;
transform: rotate(-45deg);
}
/* img.emoji {
vertical-align: middle !important;
} */
}
}
poll-element { poll-element {
margin-top: -1px; margin-top: -1px;

2
src/scss/partials/_fonts.scss

@ -129,7 +129,7 @@
content: "\e91f"; content: "\e91f";
} }
.tgico-next:before { .tgico-next:before {
content: "\e920"; content: $tgico-next;
} }
.tgico-nosound:before { .tgico-nosound:before {
content: "\e921"; content: "\e921";

1
src/scss/partials/_ico.scss

@ -5,3 +5,4 @@ $tgico-check: "\e900";
$tgico-checks: "\e95a"; $tgico-checks: "\e95a";
$tgico-sending: "\e919"; $tgico-sending: "\e919";
$tgico-close: "\e943"; $tgico-close: "\e943";
$tgico-next: "\e920";

67
src/scss/partials/_mediaViewer.scss

@ -1,3 +1,7 @@
$open-duration: .2s;
//$open-duration: 10s;
$move-duration: .35s;
.media-viewer { .media-viewer {
position: fixed; position: fixed;
top: 0; top: 0;
@ -20,7 +24,7 @@
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
color: #8b8b8b; color: #8b8b8b;
transition: .2s; transition: $open-duration;
&:hover { &:hover {
color: #fff; color: #fff;
@ -53,7 +57,7 @@
.btn-icon { .btn-icon {
margin: 0 .25rem; margin: 0 .25rem;
transition: .2s; transition: $open-duration;
&:hover { &:hover {
color: #fff; color: #fff;
@ -91,14 +95,6 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
visibility: hidden; visibility: hidden;
&.loading {
img, video {
object-fit: cover;
width: 100%;
height: 100%;
}
}
} }
img, video { img, video {
@ -108,22 +104,11 @@
max-width: 1280px; */ max-width: 1280px; */
} }
img {
object-fit: contain;
}
video {
width: 100%;
height: 100%;
/* object-fit: cover; */
object-fit: contain;
}
.media-viewer-caption { .media-viewer-caption {
flex: 1; flex: 1;
text-align: center; text-align: center;
color: $color-gray; color: $color-gray;
transition: .2s; transition: $open-duration;
max-width: 50vw; max-width: 50vw;
word-break: break-word; word-break: break-word;
overflow: hidden; overflow: hidden;
@ -165,7 +150,7 @@
top: 50%; top: 50%;
transform: translateY(-50%) rotate(90deg); transform: translateY(-50%) rotate(90deg);
opacity: 0; opacity: 0;
transition: .2s opacity; transition: $open-duration opacity;
z-index: 5; z-index: 5;
/* box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07); */ /* box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07); */
} }
@ -189,40 +174,40 @@
transform-origin: top left; transform-origin: top left;
overflow: hidden; overflow: hidden;
//border-radius: 0; //border-radius: 0;
background-repeat: no-repeat;
background-size: cover;
background-position: center center;
.ckin__player { .ckin__player {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute;
left: 0;
top: 0;
} }
img, video { img, video {
width: 100%; width: 100%;
height: 100%; height: 100%;
opacity: 1;
transition: .2s opacity;
user-select: none; user-select: none;
} object-fit: cover;
&.cover {
align-items: center;
img, video {
width: auto;
height: auto;
overflow: hidden;
opacity: 0;
}
} }
&.active { &.active {
transition: .2s transform; transition: $open-duration transform;
} }
&.moving { &.moving {
transition: 350ms transform ease; transition: $move-duration transform ease;
} }
} }
// возможно тут это вообще не нужно
&-aspecter {
width: 100%;
height: 100%;
transform: scale(1);
overflow: hidden;
}
&-mover.active &-aspecter {
transition: $open-duration all;
}
} }

19
src/scss/partials/_rightSIdebar.scss

@ -211,7 +211,7 @@
flex-direction: column; flex-direction: column;
padding: 4px 7.5px 7.5px; padding: 4px 7.5px 7.5px;
> div { .media-row {
display: grid; display: grid;
grid-template-columns: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
grid-auto-rows: max-content; grid-auto-rows: max-content;
@ -219,14 +219,9 @@
place-items: start; place-items: start;
padding-top: 3.5px; padding-top: 3.5px;
> div { .media-item {
width: 100%; width: 100%;
cursor: pointer; cursor: pointer;
background-repeat: no-repeat;
background-size: cover;
background-position: center center;
display: flex; display: flex;
background-color: #000; background-color: #000;
position: relative; position: relative;
@ -241,8 +236,8 @@
} }
} }
span.video-time { .video-time {
position: relative; position: absolute;
left: 5px; left: 5px;
top: 4px; top: 4px;
height: 18px; height: 18px;
@ -254,6 +249,12 @@
color: white; color: white;
} }
.media-image {
width: 100%;
max-height: 100%;
object-fit: cover;
}
/* span.video-play { /* span.video-play {
background-color: $time-background; background-color: $time-background;
color: #fff; color: #fff;

4
src/scss/partials/_selector.scss

@ -14,9 +14,11 @@
flex-direction: column; flex-direction: column;
&-search-container { &-search-container {
flex: 1 1 auto; flex: 0 0 auto;
//flex: 1 1 auto;
position: relative; position: relative;
max-height: 132px; max-height: 132px;
overflow: hidden;
.scrollable { .scrollable {
position: relative; position: relative;

31
src/scss/style.scss

@ -276,6 +276,37 @@ input {
} }
} }
@keyframes fadeInFadeOut {
0% {
opacity: 0;
}
10% {
opacity: 1;
}
50% {
opacity: 1;
}
to {
opacity: 0;
}
}
.toast {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: .5rem 1rem;
background-color: rgba(0, 0, 0, .66);
color: #fff;
font-size: 1rem;
border-radius: $border-radius-medium;
animation: fadeInFadeOut 3s linear forwards;
}
hr { hr {
width: 100%; width: 100%;
border: none; border: none;

1
webpack.common.js

@ -115,6 +115,7 @@ module.exports = {
filename: `index.html`, filename: `index.html`,
template: 'public/index_template.html', template: 'public/index_template.html',
inject: true, inject: true,
//inject: 'head',
/* minify: { /* minify: {
removeComments: true, removeComments: true,
collapseWhitespace: true, collapseWhitespace: true,

Loading…
Cancel
Save