Browse Source

Search messages pagination

master
Eduard Kuzmenko 5 years ago
parent
commit
70324b96ad
  1. BIN
      .DS_Store
  2. 1
      .gitignore
  3. 139
      src/components/misc.ts
  4. 18
      src/lib/appManagers/appDialogsManager.ts
  5. 110
      src/lib/appManagers/appImManager.ts
  6. 32
      src/lib/appManagers/appMediaViewer.ts
  7. 16
      src/lib/appManagers/appMessagesManager.ts
  8. 12
      src/lib/appManagers/appPhotosManager.ts
  9. 153
      src/lib/appManagers/appSidebarLeft.ts
  10. 1
      src/lib/appManagers/appSidebarRight.ts
  11. 12
      src/lib/services.ts
  12. 11
      src/scss/partials/_chat.scss
  13. 130
      src/scss/style.scss
  14. 9665
      stats.json

BIN
.DS_Store vendored

Binary file not shown.

1
.gitignore vendored

@ -2,3 +2,4 @@ node_modules
coverage coverage
__pycache__ __pycache__
dist dist
.DS_Store

139
src/components/misc.ts

@ -5,6 +5,8 @@ import CryptoWorker from '../lib/crypto/cryptoworker';
import LottieLoader from '../lib/lottieLoader'; import LottieLoader from '../lib/lottieLoader';
import appStickersManager from "../lib/appManagers/appStickersManager"; import appStickersManager from "../lib/appManagers/appStickersManager";
import appDocsManager from "../lib/appManagers/appDocsManager"; import appDocsManager from "../lib/appManagers/appDocsManager";
import {AppImManager} from "../lib/appManagers/appImManager";
import {AppMediaViewer} from '../lib/appManagers/appMediaViewer';
export type MTDocument = { export type MTDocument = {
_: 'document', _: 'document',
@ -39,50 +41,50 @@ export type MTPhotoSize = {
let onRippleClick = function(this: HTMLElement, e: MouseEvent) { let onRippleClick = function(this: HTMLElement, e: MouseEvent) {
var $circle = this.firstElementChild as HTMLSpanElement;//this.querySelector('.c-ripple__circle') as HTMLSpanElement; var $circle = this.firstElementChild as HTMLSpanElement;//this.querySelector('.c-ripple__circle') as HTMLSpanElement;
var rect = this.parentElement.getBoundingClientRect(); var rect = this.parentElement.getBoundingClientRect();
var x = e.clientX - rect.left; //x position within the element. var x = e.clientX - rect.left; //x position within the element.
var y = e.clientY - rect.top; var y = e.clientY - rect.top;
/* var x = e.pageX - this.parentElement.offsetLeft; /* var x = e.pageX - this.parentElement.offsetLeft;
var y = e.pageY - this.parentElement.offsetTop - this.parentElement.scrollHeight; */ var y = e.pageY - this.parentElement.offsetTop - this.parentElement.scrollHeight; */
$circle.style.top = y + 'px'; $circle.style.top = y + 'px';
$circle.style.left = x + 'px'; $circle.style.left = x + 'px';
this.classList.add('active'); this.classList.add('active');
//console.log('onrippleclick', e/* e.pageY, this.parentElement.offsetTop */); //console.log('onrippleclick', e/* e.pageY, this.parentElement.offsetTop */);
}; };
export function ripple(elem: Element) { export function ripple(elem: Element) {
/* elem.addEventListener('click', function(e) { /* elem.addEventListener('click', function(e) {
var $circle = elem.querySelector('.c-ripple__circle') as HTMLSpanElement; var $circle = elem.querySelector('.c-ripple__circle') as HTMLSpanElement;
var x = e.pageX - elem.offsetLeft; var x = e.pageX - elem.offsetLeft;
var y = e.pageY - elem.offsetTop; var y = e.pageY - elem.offsetTop;
$circle.style.top = y + 'px'; $circle.style.top = y + 'px';
$circle.style.left = x + 'px'; $circle.style.left = x + 'px';
elem.classList.add('active'); elem.classList.add('active');
}); */ }); */
let r = document.createElement('div'); let r = document.createElement('div');
r.classList.add('c-ripple'); r.classList.add('c-ripple');
let span = document.createElement('span'); let span = document.createElement('span');
span.classList.add('c-ripple__circle'); span.classList.add('c-ripple__circle');
r.append(span); r.append(span);
elem.append(r); elem.append(r);
r.addEventListener('click', onRippleClick); r.addEventListener('click', onRippleClick);
let onEnd = () => { let onEnd = () => {
r.classList.remove('active'); r.classList.remove('active');
}; };
for(let type of ['animationend', 'webkitAnimationEnd', 'oanimationend', 'MSAnimationEnd']) { for(let type of ['animationend', 'webkitAnimationEnd', 'oanimationend', 'MSAnimationEnd']) {
r.addEventListener(type, onEnd); r.addEventListener(type, onEnd);
} }
@ -213,9 +215,20 @@ export class LazyLoadQueue {
} }
} }
export function wrapVideo(doc: MTDocument, container: HTMLDivElement, middleware: () => boolean, messageID: number, justLoader = true, preloader?: ProgressivePreloader) { export function wrapVideo(this: any, doc: MTDocument, container: HTMLDivElement, message: any, justLoader = true, preloader?: ProgressivePreloader) {
if(!container.firstElementChild || container.firstElementChild.tagName != 'IMG') { //if(!container.firstElementChild || container.firstElementChild.tagName != 'IMG') {
let size = appPhotosManager.setAttachmentSize(doc, container); let size = appPhotosManager.setAttachmentSize(doc, container);
//}
let peerID = this.peerID ? this.peerID : this.currentMessageID;
//container.classList.add('video');
let img = container.firstElementChild as HTMLImageElement || new Image();
img.setAttribute('message-id', '' + message.id);
if(!container.contains(img)) {
container.append(img);
} }
//return Promise.resolve(); //return Promise.resolve();
@ -227,17 +240,18 @@ export function wrapVideo(doc: MTDocument, container: HTMLDivElement, middleware
let loadVideo = () => { let loadVideo = () => {
let promise = appDocsManager.downloadDoc(doc); let promise = appDocsManager.downloadDoc(doc);
promise.notify = (details: {done: number, total: number}) => { /* promise.notify = (details: {done: number, total: number}) => {
console.log('doc download', promise, details); console.log('doc download', promise, details);
preloader.setProgress(details.done); preloader.setProgress(details.done);
}; }; */
return promise.then(blob => { return promise.then(blob => {
if(!middleware()) { if((this.peerID ? this.peerID : this.currentMessageID) != peerID) {
this.log.warn('peer changed');
return; return;
} }
console.log('loaded doc:', doc, blob, container.firstElementChild); console.log('loaded doc:', doc, blob, container);
let video = document.createElement('video'); let video = document.createElement('video');
video.loop = true; video.loop = true;
@ -245,52 +259,50 @@ export function wrapVideo(doc: MTDocument, container: HTMLDivElement, middleware
if(!justLoader) { if(!justLoader) {
video.controls = true; video.controls = true;
} else {
video.volume = 0;
} }
video.setAttribute('message-id', '' + messageID); video.setAttribute('message-id', '' + message.id);
let source = document.createElement('source'); let source = document.createElement('source');
//source.src = doc.url; //source.src = doc.url;
source.src = URL.createObjectURL(blob); source.src = URL.createObjectURL(blob);
source.type = doc.mime_type; source.type = doc.mime_type;
if(img && container.contains(img)) {
container.removeChild(img);
}
video.append(source); video.append(source);
container.append(video); container.append(video);
if(container.firstElementChild) {
container.firstElementChild.remove();
}
preloader.detach(); preloader.detach();
}); });
}; };
if(doc.type == 'gif') { if(doc.type == 'gif') {
return loadVideo(); return this.peerID ? this.loadMediaQueuePush(loadVideo) : loadVideo();
} else { // if video } else { // if video
return appPhotosManager.preloadPhoto(doc).then((blob) => { let load = () => appPhotosManager.preloadPhoto(doc).then((blob) => {
if(!middleware()) { if((this.peerID ? this.peerID : this.currentMessageID) != peerID) {
this.log.warn('peer changed');
return; return;
} }
if(container.firstElementChild) { img.src = URL.createObjectURL(blob);
container.firstElementChild.remove();
}
let image = new Image();
image.src = URL.createObjectURL(blob);
/* image.style.height = doc.h + 'px'; /* image.style.height = doc.h + 'px';
image.style.width = doc.w + 'px'; */ image.style.width = doc.w + 'px'; */
image.setAttribute('message-id', '' + messageID);
container.append(image);
if(!justLoader) { if(!justLoader) {
return loadVideo(); return loadVideo();
} else {
preloader.detach();
} }
}); });
return this.peerID ? this.loadMediaQueuePush(load) : load();
} }
} }
@ -335,10 +347,10 @@ export function scrollable(el: HTMLDivElement, x = false, y = true) {
container.classList.add('scrollable'); container.classList.add('scrollable');
if(x) container.classList.add('scrollable-x'); if(x) container.classList.add('scrollable-x');
if(y) container.classList.add('scrollable-y'); if(y) container.classList.add('scrollable-y');
container.addEventListener('mouseover', () => { container.addEventListener('mouseover', () => {
container.classList.add('active'); container.classList.add('active');
container.addEventListener('mouseout', () => { container.addEventListener('mouseout', () => {
container.classList.remove('active'); container.classList.remove('active');
}, {once: true}); }, {once: true});
@ -350,6 +362,37 @@ export function scrollable(el: HTMLDivElement, x = false, y = true) {
return container; return container;
} }
export function wrapPhoto(this: AppImManager, photo: any, message: any, container: HTMLDivElement) {
//container.classList.add('photo');
let peerID = this.peerID;
let size = appPhotosManager.setAttachmentSize(photo.id, container);
let image = container.firstElementChild as HTMLImageElement || new Image();
image.setAttribute('message-id', message.mid);
if(!container.contains(image)) {
container.append(image);
}
let preloader = new ProgressivePreloader(container, false);
let load = () => appPhotosManager.preloadPhoto(photo.id, size).then((blob) => {
if(this.peerID != peerID) {
this.log.warn('peer changed');
return;
}
image.src = URL.createObjectURL(blob);
preloader.detach();
});
console.log('wrapPhoto', load, container, image);
return this.loadMediaQueue ? this.loadMediaQueuePush(load) : load();
}
export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: () => boolean, lazyLoadQueue?: LazyLoadQueue, group?: string, canvas?: boolean) { export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: () => boolean, lazyLoadQueue?: LazyLoadQueue, group?: string, canvas?: boolean) {
let stickerType = doc.mime_type == "application/x-tgsticker" ? 2 : (doc.mime_type == "image/webp" ? 1 : 0); let stickerType = doc.mime_type == "application/x-tgsticker" ? 2 : (doc.mime_type == "image/webp" ? 1 : 0);
@ -399,24 +442,24 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
animationData: JSON.parse(json), animationData: JSON.parse(json),
renderer: canvas ? 'canvas' : 'svg' renderer: canvas ? 'canvas' : 'svg'
}, group); }, group);
if(!canvas) { if(!canvas) {
div.addEventListener('mouseover', (e) => { div.addEventListener('mouseover', (e) => {
let animation = LottieLoader.getAnimation(div, group); let animation = LottieLoader.getAnimation(div, group);
if(animation) { if(animation) {
//console.log('sticker hover', animation, div); //console.log('sticker hover', animation, div);
// @ts-ignore // @ts-ignore
animation.loop = true; animation.loop = true;
// @ts-ignore // @ts-ignore
if(animation.currentFrame == animation.totalFrames - 1) { if(animation.currentFrame == animation.totalFrames - 1) {
animation.goToAndPlay(0, true); animation.goToAndPlay(0, true);
} else { } else {
animation.play(); animation.play();
} }
div.addEventListener('mouseout', () => { div.addEventListener('mouseout', () => {
// @ts-ignore // @ts-ignore
animation.loop = false; animation.loop = false;
@ -451,11 +494,11 @@ export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement,
tabs.addEventListener('click', function(e) { tabs.addEventListener('click', function(e) {
let target = e.target as HTMLLIElement; let target = e.target as HTMLLIElement;
if(target.tagName != 'LI') { if(target.tagName != 'LI') {
target = findUpTag(target, 'LI'); target = findUpTag(target, 'LI');
} }
console.log('tabs click:', target); console.log('tabs click:', target);
if(target.classList.contains('active')) return false; if(target.classList.contains('active')) return false;

18
src/lib/appManagers/appDialogsManager.ts

@ -2,13 +2,23 @@ import { MTProto } from "../mtproto/mtproto";
import { $rootScope, findUpTag } from "../utils"; import { $rootScope, findUpTag } from "../utils";
import appImManager from "./appImManager"; import appImManager from "./appImManager";
import appPeersManager from './appPeersManager'; import appPeersManager from './appPeersManager';
import { DialogDom } from "../services";
import appMessagesManager from "./appMessagesManager"; import appMessagesManager from "./appMessagesManager";
import appUsersManager from "./appUsersManager"; import appUsersManager from "./appUsersManager";
import appSidebarRight from "./appSidebarRight"; import appSidebarRight from "./appSidebarRight";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import { ripple } from "../../components/misc"; import { ripple } from "../../components/misc";
type DialogDom = {
avatarDiv: HTMLDivElement,
captionDiv: HTMLDivElement,
titleSpan: HTMLSpanElement,
statusSpan: HTMLSpanElement,
lastTimeSpan: HTMLSpanElement,
unreadMessagesSpan: HTMLSpanElement,
lastMessageSpan: HTMLSpanElement,
listEl: HTMLLIElement
};
export class AppDialogsManager { export class AppDialogsManager {
public pinnedChatList = document.getElementById('dialogs-pinned') as HTMLUListElement; public pinnedChatList = document.getElementById('dialogs-pinned') as HTMLUListElement;
public chatList = document.getElementById('dialogs') as HTMLUListElement; public chatList = document.getElementById('dialogs') as HTMLUListElement;
@ -190,13 +200,13 @@ export class AppDialogsManager {
} }
if(document.type == 'video') { if(document.type == 'video') {
lastMessageText += '<i>Video</i>'; lastMessageText = '<i>Video' + (lastMessage.message ? ', ' : '') + '</i>';
found = true; found = true;
} else if(document.type == 'voice') { } else if(document.type == 'voice') {
lastMessageText += '<i>Voice message</i>'; lastMessageText = '<i>Voice message</i>';
found = true; found = true;
} else if(document.type == 'gif') { } else if(document.type == 'gif') {
lastMessageText += '<i>GIF</i>'; lastMessageText = '<i>GIF' + (lastMessage.message ? ', ' : '') + '</i>';
found = true; found = true;
} }

110
src/lib/appManagers/appImManager.ts

@ -4,7 +4,7 @@ import appUsersManager from "./appUsersManager";
import appMessagesManager from "./appMessagesManager"; import appMessagesManager from "./appMessagesManager";
import appPeersManager from "./appPeersManager"; import appPeersManager from "./appPeersManager";
import appProfileManager from "./appProfileManager"; import appProfileManager from "./appProfileManager";
import { ProgressivePreloader, wrapDocument, wrapSticker, wrapVideo } from "../../components/misc"; import { ProgressivePreloader, wrapDocument, wrapSticker, wrapVideo, wrapPhoto } from "../../components/misc";
import appDialogsManager from "./appDialogsManager"; import appDialogsManager from "./appDialogsManager";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import appPhotosManager from "./appPhotosManager"; import appPhotosManager from "./appPhotosManager";
@ -121,7 +121,7 @@ export class AppImManager {
public scroll: HTMLDivElement = null; public scroll: HTMLDivElement = null;
public scrollPosition: ScrollPosition = null; public scrollPosition: ScrollPosition = null;
private log: ReturnType<typeof logger>; public log: ReturnType<typeof logger>;
private preloader: ProgressivePreloader = null; private preloader: ProgressivePreloader = null;
@ -763,28 +763,9 @@ export class AppImManager {
let photo = message.media.photo; let photo = message.media.photo;
this.log('messageMediaPhoto', photo); this.log('messageMediaPhoto', photo);
bubble.classList.add('photo'); bubble.classList.add('hide-name', 'photo');
let size = appPhotosManager.setAttachmentSize(photo.id, attachmentDiv); wrapPhoto.call(this, photo, message, attachmentDiv);
let load = () => appPhotosManager.preloadPhoto(photo.id, size).then((blob) => {
if(this.peerID != peerID) {
this.log.warn('peer changed');
return;
}
if(attachmentDiv.firstElementChild) {
attachmentDiv.firstElementChild.remove();
}
let image = new Image();
image.src = URL.createObjectURL(blob);
image.setAttribute('message-id', message.mid);
attachmentDiv.append(image);
});
bubble.classList.add('hide-name');
this.loadMediaQueuePush(load);
break; break;
} }
@ -827,58 +808,18 @@ export class AppImManager {
doc = webpage.document; doc = webpage.document;
if(doc.type == 'gif' || doc.type == 'video') { if(doc.type == 'gif' || doc.type == 'video') {
appPhotosManager.setAttachmentSize(doc, preview);
bubble.classList.add('video'); bubble.classList.add('video');
wrapVideo.call(this, doc, preview, message);
let load = () => wrapVideo(doc, preview, () => {
if(this.peerID != peerID) {
this.log.warn('peer changed');
return false;
}
loadedVideo = true;
return true;
}, message.mid);
this.loadMediaQueuePush(load);
} else { } else {
doc = null; doc = null;
} }
} }
if(webpage.photo && !doc) { if(webpage.photo && !doc) {
appPhotosManager.savePhoto(webpage.photo); // hot-fix because no webpage manager
bubble.classList.add('photo'); bubble.classList.add('photo');
appPhotosManager.savePhoto(webpage.photo); // hot-fix because no webpage manager
let size = appPhotosManager.setAttachmentSize(webpage.photo.id, preview);
let load = () => appPhotosManager.preloadPhoto(webpage.photo.id, size).then((blob) => {
if(this.peerID != peerID) {
this.log.warn('peer changed');
return;
}
if(loadedVideo) {
return;
}
let img = preview.firstElementChild as HTMLImageElement || new Image();
this.log('night running 1', bubble, bubble.scrollHeight, img.src);
//setTimeout(() => {
img.src = URL.createObjectURL(blob);
///}, 5e3);
if(!preview.contains(img)) {
preview.append(img);
}
this.log('night running 2', bubble, bubble.scrollHeight);
});
this.loadMediaQueuePush(load); wrapPhoto.call(this, webpage.photo, message, preview);
} }
if(preview) { if(preview) {
@ -943,18 +884,7 @@ export class AppImManager {
this.log('never get free 2', doc); this.log('never get free 2', doc);
bubble.classList.add('video'); bubble.classList.add('video');
wrapVideo.call(this, doc, attachmentDiv, message);
appPhotosManager.setAttachmentSize(doc, attachmentDiv);
let load = () => wrapVideo(doc, attachmentDiv, () => {
if(this.peerID != peerID) {
this.log.warn('peer changed');
return false;
}
return true;
}, message.mid);
this.loadMediaQueuePush(load);
break; break;
} else { } else {
@ -1055,19 +985,21 @@ export class AppImManager {
//} //}
} }
let avatarDiv = document.createElement('div'); if(!our && this.peerID < 0) {
avatarDiv.classList.add('user-avatar'); let avatarDiv = document.createElement('div');
avatarDiv.classList.add('user-avatar');
this.log('exec loadDialogPhoto', message);
if(message.fromID) { // if no - user hidden
appDialogsManager.loadDialogPhoto(avatarDiv, message.fromID);
} else if(!title && message.fwd_from && message.fwd_from.from_name) {
title = message.fwd_from.from_name;
this.log('exec loadDialogPhoto', message); appDialogsManager.loadDialogPhoto(avatarDiv, title);
if(message.fromID) { // if no - user hidden }
appDialogsManager.loadDialogPhoto(avatarDiv, message.fromID);
} else if(!title && message.fwd_from && message.fwd_from.from_name) { bubble.append(avatarDiv);
title = message.fwd_from.from_name;
appDialogsManager.loadDialogPhoto(avatarDiv, title);
} }
bubble.append(avatarDiv);
} }
let type = our ? 'out' : 'in'; let type = our ? 'out' : 'in';

32
src/lib/appManagers/appMediaViewer.ts

@ -7,8 +7,9 @@ import { $rootScope } from "../utils";
import appMessagesManager from "./appMessagesManager"; import appMessagesManager from "./appMessagesManager";
import { CancellablePromise } from "../mtproto/apiFileManager"; import { CancellablePromise } from "../mtproto/apiFileManager";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import { logger } from "../polyfill";
class AppMediaViewer { export class AppMediaViewer {
private overlaysDiv = document.querySelector('.overlays') as HTMLDivElement; private overlaysDiv = document.querySelector('.overlays') as HTMLDivElement;
private author = { private author = {
avatarEl: this.overlaysDiv.querySelector('.user-avatar') as HTMLDivElement, avatarEl: this.overlaysDiv.querySelector('.user-avatar') as HTMLDivElement,
@ -29,17 +30,21 @@ class AppMediaViewer {
}; };
private reverse = false; private reverse = false;
private currentMessageID = 0; public currentMessageID = 0;
private higherMsgID: number | undefined = 0; private higherMsgID: number | undefined = 0;
private lowerMsgID: number | undefined = 0; private lowerMsgID: number | undefined = 0;
private preloader: ProgressivePreloader = null; private preloader: ProgressivePreloader = null;
public log: ReturnType<typeof logger>;
constructor() { constructor() {
this.log = logger('AMV');
this.preloader = new ProgressivePreloader(); this.preloader = new ProgressivePreloader();
this.buttons.close.addEventListener('click', () => { this.buttons.close.addEventListener('click', () => {
this.overlaysDiv.classList.remove('active'); this.overlaysDiv.classList.remove('active');
this.content.container.innerHTML = ''; this.content.container.innerHTML = '';
this.currentMessageID = 0;
}); });
this.buttons.prev.addEventListener('click', () => { this.buttons.prev.addEventListener('click', () => {
@ -127,7 +132,7 @@ class AppMediaViewer {
} }
public openMedia(message: any, reverse = false) { public openMedia(message: any, reverse = false) {
console.log('openMedia doc:', message); this.log('openMedia doc:', message);
let media = message.media.photo || message.media.document || message.media.webpage.document; let media = message.media.photo || message.media.document || message.media.webpage.document;
let isVideo = media.mime_type == 'video/mp4'; let isVideo = media.mime_type == 'video/mp4';
@ -138,7 +143,7 @@ class AppMediaViewer {
let container = this.content.container; let container = this.content.container;
if(container.firstElementChild) { if(container.firstElementChild) {
container.firstElementChild.remove(); container.innerHTML = '';
} }
let date = new Date(media.date * 1000); let date = new Date(media.date * 1000);
@ -163,21 +168,12 @@ class AppMediaViewer {
this.overlaysDiv.classList.add('active'); this.overlaysDiv.classList.add('active');
if(isVideo) { if(isVideo) {
appPhotosManager.setAttachmentSize(media, container); //this.preloader.attach(container);
this.preloader.attach(container);
//this.preloader.setProgress(75); //this.preloader.setProgress(75);
console.log('will wrap video'); this.log('will wrap video');
wrapVideo(media, container, () => { wrapVideo.call(this, media, container, message, false, this.preloader);
if(this.currentMessageID != message.mid) {
console.warn('media viewer changed photo');
return false;
}
return true;
}, message.mid, false, this.preloader);
} else { } else {
let size = appPhotosManager.setAttachmentSize(media.id, container, appPhotosManager.windowW, appPhotosManager.windowH); let size = appPhotosManager.setAttachmentSize(media.id, container, appPhotosManager.windowW, appPhotosManager.windowH);
@ -187,11 +183,11 @@ class AppMediaViewer {
let cancellablePromise = appPhotosManager.preloadPhoto(media.id, size); let cancellablePromise = appPhotosManager.preloadPhoto(media.id, size);
cancellablePromise.then((blob) => { cancellablePromise.then((blob) => {
if(this.currentMessageID != message.mid) { if(this.currentMessageID != message.mid) {
console.warn('media viewer changed photo'); this.log.warn('media viewer changed photo');
return; return;
} }
console.log('indochina', blob); this.log('indochina', blob);
if(container.firstElementChild) { if(container.firstElementChild) {
container.firstElementChild.remove(); container.firstElementChild.remove();
} }

16
src/lib/appManagers/appMessagesManager.ts

@ -1639,7 +1639,11 @@ export class AppMessagesManager {
public getSearch(peerID = 0, query: string = '', inputFilter: { public getSearch(peerID = 0, query: string = '', inputFilter: {
_?: string _?: string
} = {_: 'inputMessagesFilterEmpty'}, maxID: number, limit: number) { } = {_: 'inputMessagesFilterEmpty'}, maxID: number, limit: number, offsetRate = 0): Promise<{
count: number,
next_rate: number,
history: number[]
}> {
//peerID = peerID ? parseInt(peerID) : 0; //peerID = peerID ? parseInt(peerID) : 0;
var foundMsgs: number[] = []; var foundMsgs: number[] = [];
var useSearchCache = !query; var useSearchCache = !query;
@ -1713,6 +1717,7 @@ export class AppMessagesManager {
default: default:
return Promise.resolve({ return Promise.resolve({
count: 0, count: 0,
next_rate: 0,
history: [] as number[] history: [] as number[]
}); });
} }
@ -1756,6 +1761,7 @@ export class AppMessagesManager {
return Promise.resolve({ return Promise.resolve({
count: 0, count: 0,
next_rate: 0,
history: foundMsgs history: foundMsgs
}); });
} }
@ -1793,7 +1799,7 @@ export class AppMessagesManager {
apiPromise = MTProto.apiManager.invokeApi('messages.searchGlobal', { apiPromise = MTProto.apiManager.invokeApi('messages.searchGlobal', {
q: query, q: query,
offset_date: offsetDate, 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
@ -1808,6 +1814,8 @@ export class AppMessagesManager {
appChatsManager.saveApiChats(searchResult.chats); appChatsManager.saveApiChats(searchResult.chats);
this.saveMessages(searchResult.messages); this.saveMessages(searchResult.messages);
console.log('messages.search result:', searchResult);
var foundCount: number = searchResult.count || searchResult.messages.length; var foundCount: number = searchResult.count || searchResult.messages.length;
foundMsgs = []; foundMsgs = [];
@ -1830,12 +1838,14 @@ export class AppMessagesManager {
return { return {
count: foundCount, count: foundCount,
next_rate: searchResult.next_rate,
history: foundMsgs history: foundMsgs
} };
}, (error) => { }, (error) => {
if(error.code == 400) { if(error.code == 400) {
error.handled = true; error.handled = true;
} }
return Promise.reject(error); return Promise.reject(error);
}); });
} }

12
src/lib/appManagers/appPhotosManager.ts

@ -151,13 +151,13 @@ export class AppPhotosManager {
let image = new Image(); let image = new Image();
image.src = URL.createObjectURL(blob); image.src = URL.createObjectURL(blob);
image.style.width = '100%'; // image.style.width = '100%';
image.style.height = '100%'; // image.style.height = '100%';
div.append(image); div.append(image);
} }
} }
public setAttachmentSize(photoID: any, div: HTMLDivElement, w = 380, h = 0) { public setAttachmentSize(photoID: any, div: HTMLDivElement, w = 380, h = 0/* 380 */) {
let photo: /* MTDocument | MTPhoto */any = null; let photo: /* MTDocument | MTPhoto */any = null;
if(typeof(photoID) === 'string') { if(typeof(photoID) === 'string') {
@ -170,11 +170,9 @@ export class AppPhotosManager {
let photoSize = this.choosePhotoSize(photo, w, h); let photoSize = this.choosePhotoSize(photo, w, h);
//console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div); //console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);
let thumb: any;
let sizes = photo.sizes || photo.thumbs; let sizes = photo.sizes || photo.thumbs;
if(sizes && (sizes[0]._ == 'photoStrippedSize' || sizes[0]._ == 'photoCachedSize' && sizes[0].bytes)) { if(sizes && sizes[0].bytes) {
thumb = sizes[0]; this.setAttachmentPreview(sizes[0].bytes, div);
this.setAttachmentPreview(thumb.bytes, div);
} }
if(photo._ == 'document' /* && photo.type != 'video' */ && photo.type != 'gif') { if(photo._ == 'document' /* && photo.type != 'video' */ && photo.type != 'gif') {

153
src/lib/appManagers/appSidebarLeft.ts

@ -2,91 +2,88 @@ import { logger } from "../polyfill";
import { scrollable } from "../../components/misc"; import { scrollable } from "../../components/misc";
import appMessagesManager from "./appMessagesManager"; import appMessagesManager from "./appMessagesManager";
import appDialogsManager from "./appDialogsManager"; import appDialogsManager from "./appDialogsManager";
import { isElementInViewport } from "../utils";
import appMessagesIDsManager from "./appMessagesIDsManager";
class AppSidebarLeft { class AppSidebarLeft {
private sidebarEl = document.querySelector('.page-chats .chats-container') as HTMLDivElement; private sidebarEl = document.querySelector('.page-chats .chats-container') as HTMLDivElement;
private searchInput = document.getElementById('global-search') as HTMLInputElement; private searchInput = document.getElementById('global-search') as HTMLInputElement;
private toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement; private toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement;
private searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement; private searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;
private listsContainer: HTMLDivElement = null; private listsContainer: HTMLDivElement = null;
private searchMessagesList: HTMLUListElement = null; private searchMessagesList: HTMLUListElement = null;
private log = logger('SL'); private log = logger('SL');
private peerID = 0; private peerID = 0;
private minMsgID = 0;
private loadedCount = 0;
private foundCount = 0;
private offsetRate = 0;
private searchPromise: Promise<void> = null; private searchPromise: Promise<void> = null;
private searchTimeout: number = 0;
private query = '';
constructor() { constructor() {
this.listsContainer = scrollable(this.searchContainer); this.listsContainer = scrollable(this.searchContainer);
this.searchMessagesList = document.createElement('ul'); this.searchMessagesList = document.createElement('ul');
this.listsContainer.onscroll = this.onSidebarScroll.bind(this);
this.searchContainer.append(this.listsContainer); this.searchContainer.append(this.listsContainer);
appDialogsManager.setListClickListener(this.searchMessagesList); appDialogsManager.setListClickListener(this.searchMessagesList);
this.searchInput.addEventListener('focus', (e) => { this.searchInput.addEventListener('focus', (e) => {
this.toolsBtn.classList.remove('tgico-menu'); this.toolsBtn.classList.remove('tgico-menu');
this.toolsBtn.classList.add('tgico-back'); this.toolsBtn.classList.add('tgico-back');
this.searchContainer.classList.add('active'); this.searchContainer.classList.add('active');
if(!this.searchInput.value) { if(!this.searchInput.value) {
this.searchMessagesList.innerHTML = ''; this.searchMessagesList.innerHTML = '';
} }
this.searchInput.addEventListener('blur', (e) => { this.searchInput.addEventListener('blur', (e) => {
if(!this.searchInput.value) { if(!this.searchInput.value) {
this.toolsBtn.classList.add('tgico-menu'); this.toolsBtn.classList.add('tgico-menu');
this.toolsBtn.classList.remove('tgico-back'); this.toolsBtn.classList.remove('tgico-back');
this.searchContainer.classList.remove('active'); this.searchContainer.classList.remove('active');
} }
this.peerID = 0; /* this.peerID = 0;
this.loadedCount = 0;
this.minMsgID = 0; */
}, {once: true}); }, {once: true});
}); });
this.searchInput.addEventListener('input', (e) => { this.searchInput.addEventListener('input', (e) => {
//console.log('messageInput input', this.innerText, serializeNodes(Array.from(messageInput.childNodes))); //console.log('messageInput input', this.innerText, serializeNodes(Array.from(messageInput.childNodes)));
let value = this.searchInput.value; let value = this.searchInput.value;
this.log('input', value); this.log('input', value);
if(this.listsContainer.contains(this.searchMessagesList)) { if(this.listsContainer.contains(this.searchMessagesList)) {
this.listsContainer.removeChild(this.searchMessagesList) this.listsContainer.removeChild(this.searchMessagesList)
} }
if(!value.trim()) { if(!value.trim()) {
return; return;
} }
appMessagesManager.getSearch(this.peerID, value, null, 0, 20).then(res => { this.query = value;
if(this.searchInput.value != value) { this.minMsgID = 0;
return; this.loadedCount = 0;
} this.foundCount = 0;
this.offsetRate = 0;
this.log('input search result:', res); this.searchMessagesList.innerHTML = '';
this.searchPromise = null;
let {count, history} = res; this.searchMore().then(() => {
this.searchMessagesList.innerHTML = '';
history.forEach((msgID: number) => {
let message = appMessagesManager.getMessage(msgID);
let originalDialog = appMessagesManager.getDialogByPeerID(message.peerID)[0];
if(!originalDialog) {
this.log.warn('no original dialog by message:', msgID);
return;
}
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, this.searchMessagesList, false);
appDialogsManager.setLastMessage(dialog, message, dom);
});
this.listsContainer.append(this.searchMessagesList); this.listsContainer.append(this.searchMessagesList);
}); });
}); });
this.toolsBtn.addEventListener('click', () => { this.toolsBtn.addEventListener('click', () => {
if(this.toolsBtn.classList.contains('tgico-back')) { if(this.toolsBtn.classList.contains('tgico-back')) {
this.searchInput.value = ''; this.searchInput.value = '';
@ -95,15 +92,89 @@ class AppSidebarLeft {
this.searchContainer.classList.remove('active'); this.searchContainer.classList.remove('active');
} }
}); });
}
window.addEventListener('resize', () => {
setTimeout(() => this.onSidebarScroll(), 0);
});
}
public onSidebarScroll() {
let elements = Array.from(this.searchMessagesList.childNodes).slice(-5);
for(let li of elements) {
if(isElementInViewport(li)) {
this.log('Will load more search');
if(!this.searchTimeout) {
this.searchTimeout = setTimeout(() => {
this.searchMore();
this.searchTimeout = 0;
}, 0);
}
break;
}
}
}
public beginSearch(peerID?: number) { public beginSearch(peerID?: number) {
if(peerID) { if(peerID) {
this.peerID = peerID; this.peerID = peerID;
} }
this.searchInput.focus(); this.searchInput.focus();
} }
private searchMore() {
if(this.searchPromise) return this.searchPromise;
let query = this.query;
if(this.loadedCount != 0 && this.loadedCount >= this.foundCount) {
return Promise.resolve();
}
let maxID = 0;//appMessagesIDsManager.getMessageIDInfo(this.minMsgID)[0] - 1;
return this.searchPromise = appMessagesManager.getSearch(this.peerID, query, null, maxID, 20, this.offsetRate).then(res => {
this.searchPromise = null;
if(this.searchInput.value != query) {
return;
}
this.log('input search result:', this.peerID, query, null, maxID, 20, res);
let {count, history, next_rate} = res;
if(history[0] == this.minMsgID) {
history.shift();
}
history.forEach((msgID: number) => {
let message = appMessagesManager.getMessage(msgID);
let originalDialog = appMessagesManager.getDialogByPeerID(message.peerID)[0];
if(!originalDialog) {
this.log.warn('no original dialog by message:', msgID);
return;
}
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, this.searchMessagesList, false);
appDialogsManager.setLastMessage(dialog, message, dom);
});
this.minMsgID = history[history.length - 1];
this.offsetRate = next_rate;
this.loadedCount += history.length;
if(!this.foundCount) {
this.foundCount = count;
}
}).catch(err => {
this.log.error('search error', err);
this.searchPromise = null;
});
}
} }
export default new AppSidebarLeft(); export default new AppSidebarLeft();

1
src/lib/appManagers/appSidebarRight.ts

@ -9,7 +9,6 @@ import { RichTextProcessor } from "../richtextprocessor";
import { logger } from "../polyfill"; import { logger } from "../polyfill";
import appImManager from "./appImManager"; import appImManager from "./appImManager";
import appMediaViewer from "./appMediaViewer"; import appMediaViewer from "./appMediaViewer";
import appDocsManager from "./appDocsManager";
class AppSidebarRight { class AppSidebarRight {
public sidebarEl = document.querySelector('.profile-container') as HTMLDivElement; public sidebarEl = document.querySelector('.profile-container') as HTMLDivElement;

12
src/lib/services.ts

@ -30,18 +30,6 @@ export const appStickersManager = AppStickersManager;
export const appSidebarRight = AppSidebarRight; export const appSidebarRight = AppSidebarRight;
export const appSidebarLeft = AppSidebarLeft; export const appSidebarLeft = AppSidebarLeft;
export type DialogDom = {
avatarDiv: HTMLDivElement,
captionDiv: HTMLDivElement,
titleSpan: HTMLSpanElement,
statusSpan: HTMLSpanElement,
lastTimeSpan: HTMLSpanElement,
unreadMessagesSpan: HTMLSpanElement,
lastMessageSpan: HTMLSpanElement,
listEl: HTMLLIElement
};
(window as any).Services = { (window as any).Services = {
appUsersManager, appUsersManager,
appChatsManager, appChatsManager,

11
src/scss/partials/_chat.scss

@ -237,7 +237,8 @@
.box.web { .box.web {
width: min-content; width: min-content;
max-width: min-content; /* max-width: min-content; */
max-width: 100%;
} }
} }
@ -248,7 +249,8 @@
} }
img, video { img, video {
object-fit: contain; /* object-fit: contain; */
object-fit: cover;
} }
.emoji { .emoji {
@ -361,14 +363,17 @@
&:not(.sticker) { &:not(.sticker) {
.attachment { .attachment {
max-width: 380px; max-width: 380px;
max-height: 380px;
} }
} }
&.video { &.video {
.attachment { .attachment {
//max-height: fit-content;
img { img {
width: 100%; width: 100%;
height: 100%; /* height: 100%; */
} }
} }
} }

130
src/scss/style.scss

@ -32,6 +32,7 @@ $time-size: 12px;
@import "partials/chat"; @import "partials/chat";
@import "partials/sidebar"; @import "partials/sidebar";
@import "partials/leftSidebar"; @import "partials/leftSidebar";
@import "partials/mediaViewer";
html, body { html, body {
height: 100%; height: 100%;
@ -1077,136 +1078,7 @@ $width: 100px;
} }
} }
.media-viewer {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, .9);
/* color: $darkgrey; */
display: flex;
align-items: center;
justify-content: center;
.media-viewer-author {
position: absolute;
top: 0;
left: 0;
height: 60px;
padding: 8px 8px 8px 80px;
display: flex;
flex-direction: column;
justify-content: center;
color: #8b8b8b;
.user-avatar {
width: 44px;
height: 44px;
position: absolute;
top: 8px;
left: 20px;
}
.media-viewer-name {
font-weight: 500;
}
.media-viewer-date {
font-size: 15px;
}
}
.media-viewer-buttons {
position: absolute;
top: 0;
right: 0;
display: flex;
flex-flow: row nowrap;
padding: 8px;
.btn-icon {
margin: 0 .25rem;
}
}
.media-viewer-content {
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
.media-viewer-stub {
flex: 1;
}
.media-viewer-container {
align-self: center;
position: relative;
}
.media-viewer-media {
display: flex;
align-items: center;
justify-content: center;
> img, > video {
max-height: calc(100vh - 100px);
max-width: calc(100vw - 16px);
}
}
.media-viewer-switcher-left, .media-viewer-switcher-right {
position: absolute;
left: 0;
top: 0;
width: 10rem;
height: 100%;
cursor: pointer;
&:hover {
> span {
opacity: 1;
}
}
}
.media-viewer-switcher-right {
left: auto;
right: 0;
}
.media-viewer-prev-button, .media-viewer-next-button {
cursor: pointer;
position: absolute;
color: #fff;
font-size: 3rem;
left: 2rem;
top: 50%;
transform: translateY(-50%) rotate(90deg);
opacity: 0;
transition: .2s opacity;
z-index: 3;
/* box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07); */
}
.media-viewer-next-button {
left: auto;
right: 2rem;
transform: translateY(-50%) rotate(-90deg);
}
.media-viewer-caption {
flex: 1;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: $darkgrey;
}
}
}
div.scrollable-y::-webkit-scrollbar { div.scrollable-y::-webkit-scrollbar {
/* width: 4px; */ /* width: 4px; */

9665
stats.json

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save