Fix displaying chat from the archive in main list
This commit is contained in:
parent
34546d49ee
commit
8992a6e7af
80
src/components/chat/audio.ts
Normal file
80
src/components/chat/audio.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import appImManager from "../../lib/appManagers/appImManager";
|
||||
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||
import appPeersManager from "../../lib/appManagers/appPeersManager";
|
||||
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||
import { cancelEvent, $rootScope } from "../../lib/utils";
|
||||
import appMediaPlaybackController from "../appMediaPlaybackController";
|
||||
import { formatDate } from "../wrappers";
|
||||
|
||||
export class ChatAudio {
|
||||
public container: HTMLElement;
|
||||
private toggle: HTMLElement;
|
||||
private title: HTMLElement;
|
||||
private subtitle: HTMLElement;
|
||||
private close: HTMLElement;
|
||||
|
||||
constructor() {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('pinned-audio', 'pinned-container');
|
||||
this.container.style.display = 'none';
|
||||
|
||||
this.toggle = document.createElement('div');
|
||||
this.toggle.classList.add('pinned-audio-ico', 'tgico');
|
||||
|
||||
this.title = document.createElement('div');
|
||||
this.title.classList.add('pinned-audio-title');
|
||||
|
||||
this.subtitle = document.createElement('div');
|
||||
this.subtitle.classList.add('pinned-audio-subtitle');
|
||||
|
||||
this.close = document.createElement('button');
|
||||
this.close.classList.add('pinned-audio-close', 'btn-icon', 'tgico-close');
|
||||
|
||||
this.container.append(this.toggle, this.title, this.subtitle, this.close);
|
||||
|
||||
this.close.addEventListener('click', (e) => {
|
||||
cancelEvent(e);
|
||||
this.container.style.display = 'none';
|
||||
this.container.parentElement.classList.remove('is-audio-shown');
|
||||
if(this.toggle.classList.contains('flip-icon')) {
|
||||
appMediaPlaybackController.toggle();
|
||||
}
|
||||
});
|
||||
|
||||
this.toggle.addEventListener('click', (e) => {
|
||||
cancelEvent(e);
|
||||
appMediaPlaybackController.toggle();
|
||||
});
|
||||
|
||||
$rootScope.$on('audio_play', (e: CustomEvent) => {
|
||||
const {doc, mid} = e.detail;
|
||||
|
||||
let title: string, subtitle: string;
|
||||
if(doc.type == 'voice' || doc.type == 'round') {
|
||||
const message = appMessagesManager.getMessage(mid);
|
||||
title = appPeersManager.getPeerTitle(message.fromID, false, true);
|
||||
//subtitle = 'Voice message';
|
||||
subtitle = formatDate(message.date, false, false);
|
||||
} else {
|
||||
title = doc.audioTitle || doc.file_name;
|
||||
subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : 'Unknown Artist';
|
||||
}
|
||||
|
||||
this.title.innerHTML = title;
|
||||
this.subtitle.innerHTML = subtitle;
|
||||
this.toggle.classList.add('flip-icon');
|
||||
|
||||
this.container.dataset.mid = '' + mid;
|
||||
if(this.container.style.display) {
|
||||
const scrollTop = appImManager.scrollable.scrollTop;
|
||||
this.container.style.display = '';
|
||||
this.container.parentElement.classList.add('is-audio-shown');
|
||||
appImManager.scrollable.scrollTop = scrollTop;
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('audio_pause', () => {
|
||||
this.toggle.classList.remove('flip-icon');
|
||||
});
|
||||
}
|
||||
}
|
167
src/components/chat/contextMenu.ts
Normal file
167
src/components/chat/contextMenu.ts
Normal file
@ -0,0 +1,167 @@
|
||||
import appChatsManager from "../../lib/appManagers/appChatsManager";
|
||||
import appImManager from "../../lib/appManagers/appImManager";
|
||||
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||
import appPeersManager from "../../lib/appManagers/appPeersManager";
|
||||
import { findUpClassName, $rootScope } from "../../lib/utils";
|
||||
import appForward from "../appForward";
|
||||
import { parseMenuButtonsTo, attachContextMenuListener, positionMenu, openBtnMenu } from "../misc";
|
||||
import { PopupButton, PopupPeer } from "../popup";
|
||||
|
||||
export class ChatContextMenu {
|
||||
private element = document.getElementById('bubble-contextmenu') as HTMLDivElement;
|
||||
private buttons: {
|
||||
reply: HTMLButtonElement,
|
||||
edit: HTMLButtonElement,
|
||||
copy: HTMLButtonElement,
|
||||
pin: HTMLButtonElement,
|
||||
forward: HTMLButtonElement,
|
||||
delete: HTMLButtonElement
|
||||
} = {} as any;
|
||||
public msgID: number;
|
||||
|
||||
constructor(private attachTo: HTMLElement) {
|
||||
parseMenuButtonsTo(this.buttons, this.element.children);
|
||||
|
||||
attachContextMenuListener(attachTo, (e) => {
|
||||
let bubble: HTMLElement = null;
|
||||
|
||||
try {
|
||||
bubble = findUpClassName(e.target, 'bubble__container');
|
||||
} catch(e) {}
|
||||
|
||||
if(!bubble) return;
|
||||
|
||||
if(e instanceof MouseEvent) e.preventDefault();
|
||||
if(this.element.classList.contains('active')) {
|
||||
return false;
|
||||
}
|
||||
if(e instanceof MouseEvent) e.cancelBubble = true;
|
||||
|
||||
bubble = bubble.parentElement as HTMLDivElement; // bc container
|
||||
|
||||
let msgID = +bubble.dataset.mid;
|
||||
if(!msgID) return;
|
||||
|
||||
let peerID = $rootScope.selectedPeerID;
|
||||
this.msgID = msgID;
|
||||
|
||||
const message = appMessagesManager.getMessage(msgID);
|
||||
|
||||
this.buttons.copy.style.display = message.message ? '' : 'none';
|
||||
|
||||
if($rootScope.myID == peerID || (peerID < 0 && appChatsManager.hasRights(-peerID, 'pin'))) {
|
||||
this.buttons.pin.style.display = '';
|
||||
} else {
|
||||
this.buttons.pin.style.display = 'none';
|
||||
}
|
||||
|
||||
this.buttons.edit.style.display = appMessagesManager.canEditMessage(msgID) ? '' : 'none';
|
||||
|
||||
let side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right';
|
||||
positionMenu(e, this.element, side);
|
||||
openBtnMenu(this.element);
|
||||
|
||||
/////this.log('contextmenu', e, bubble, msgID, side);
|
||||
});
|
||||
|
||||
this.buttons.copy.addEventListener('click', () => {
|
||||
let message = appMessagesManager.getMessage(this.msgID);
|
||||
|
||||
let str = message ? message.message : '';
|
||||
|
||||
var textArea = document.createElement("textarea");
|
||||
textArea.value = str;
|
||||
textArea.style.position = "fixed"; //avoid scrolling to bottom
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
} catch (err) {
|
||||
console.error('Oops, unable to copy', err);
|
||||
}
|
||||
|
||||
document.body.removeChild(textArea);
|
||||
});
|
||||
|
||||
this.buttons.delete.addEventListener('click', () => {
|
||||
let peerID = $rootScope.selectedPeerID;
|
||||
let firstName = appPeersManager.getPeerTitle(peerID, false, true);
|
||||
|
||||
let callback = (revoke: boolean) => {
|
||||
appMessagesManager.deleteMessages([this.msgID], revoke);
|
||||
};
|
||||
|
||||
let title: string, description: string, buttons: PopupButton[];
|
||||
title = 'Delete Message?';
|
||||
description = `Are you sure you want to delete this message?`;
|
||||
|
||||
if(peerID == $rootScope.myID) {
|
||||
buttons = [{
|
||||
text: 'DELETE',
|
||||
isDanger: true,
|
||||
callback: () => callback(false)
|
||||
}];
|
||||
} else {
|
||||
buttons = [{
|
||||
text: 'DELETE JUST FOR ME',
|
||||
isDanger: true,
|
||||
callback: () => callback(false)
|
||||
}];
|
||||
|
||||
if(peerID > 0) {
|
||||
buttons.push({
|
||||
text: 'DELETE FOR ME AND ' + firstName,
|
||||
isDanger: true,
|
||||
callback: () => callback(true)
|
||||
});
|
||||
} else if(appChatsManager.hasRights(-peerID, 'deleteRevoke')) {
|
||||
buttons.push({
|
||||
text: 'DELETE FOR ALL',
|
||||
isDanger: true,
|
||||
callback: () => callback(true)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
buttons.push({
|
||||
text: 'CANCEL',
|
||||
isCancel: true
|
||||
});
|
||||
|
||||
let popup = new PopupPeer('popup-delete-chat', {
|
||||
peerID: peerID,
|
||||
title: title,
|
||||
description: description,
|
||||
buttons: buttons
|
||||
});
|
||||
|
||||
popup.show();
|
||||
});
|
||||
|
||||
this.buttons.reply.addEventListener('click', () => {
|
||||
const message = appMessagesManager.getMessage(this.msgID);
|
||||
const chatInputC = appImManager.chatInputC;
|
||||
chatInputC.setTopInfo(appPeersManager.getPeerTitle(message.fromID, true), message.message, undefined, message);
|
||||
chatInputC.replyToMsgID = this.msgID;
|
||||
chatInputC.editMsgID = 0;
|
||||
});
|
||||
|
||||
this.buttons.forward.addEventListener('click', () => {
|
||||
appForward.init([this.msgID]);
|
||||
});
|
||||
|
||||
this.buttons.edit.addEventListener('click', () => {
|
||||
const message = appMessagesManager.getMessage(this.msgID);
|
||||
const chatInputC = appImManager.chatInputC;
|
||||
chatInputC.setTopInfo('Editing', message.message, message.message, message);
|
||||
chatInputC.replyToMsgID = 0;
|
||||
chatInputC.editMsgID = this.msgID;
|
||||
});
|
||||
|
||||
this.buttons.pin.addEventListener('click', () => {
|
||||
appMessagesManager.updatePinnedMessage($rootScope.selectedPeerID, this.msgID);
|
||||
});
|
||||
}
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
import Scrollable from "./scrollable_new";
|
||||
import { RichTextProcessor } from "../lib/richtextprocessor";
|
||||
import apiManager from "../lib/mtproto/mtprotoworker";
|
||||
import appWebPagesManager from "../lib/appManagers/appWebPagesManager";
|
||||
import appImManager from "../lib/appManagers/appImManager";
|
||||
import { getRichValue, calcImageInBox, cancelEvent } from "../lib/utils";
|
||||
import { wrapDocument, wrapReply } from "./wrappers";
|
||||
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||
import { Layouter, RectPart } from "./groupedLayout";
|
||||
import Recorder from '../../public/recorder.min';
|
||||
import Scrollable from "../scrollable_new";
|
||||
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||
import apiManager from "../../lib/mtproto/mtprotoworker";
|
||||
import appWebPagesManager from "../../lib/appManagers/appWebPagesManager";
|
||||
import appImManager from "../../lib/appManagers/appImManager";
|
||||
import { getRichValue, calcImageInBox, cancelEvent } from "../../lib/utils";
|
||||
import { wrapDocument, wrapReply } from "../wrappers";
|
||||
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||
import { Layouter, RectPart } from "../groupedLayout";
|
||||
import Recorder from '../../../public/recorder.min';
|
||||
//import Recorder from '../opus-recorder/dist/recorder.min';
|
||||
import opusDecodeController from "../lib/opusDecodeController";
|
||||
import { touchSupport } from "../lib/config";
|
||||
import appDocsManager from "../lib/appManagers/appDocsManager";
|
||||
import emoticonsDropdown from "./emoticonsDropdown";
|
||||
import PopupCreatePoll from "./popupCreatePoll";
|
||||
import opusDecodeController from "../../lib/opusDecodeController";
|
||||
import { touchSupport } from "../../lib/config";
|
||||
import appDocsManager from "../../lib/appManagers/appDocsManager";
|
||||
import emoticonsDropdown from "../emoticonsDropdown";
|
||||
import PopupCreatePoll from "../popupCreatePoll";
|
||||
|
||||
export class ChatInput {
|
||||
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
||||
@ -729,7 +729,7 @@ export class ChatInput {
|
||||
|
||||
public sendMessageWithDocument(document: any) {
|
||||
document = appDocsManager.getDoc(document);
|
||||
if(document._ != 'documentEmpty') {
|
||||
if(document && document._ != 'documentEmpty') {
|
||||
appMessagesManager.sendFile(appImManager.peerID, document, {isMedia: true, replyToMsgID: this.replyToMsgID});
|
||||
this.onMessageSent(false, true);
|
||||
|
187
src/components/chat/search.ts
Normal file
187
src/components/chat/search.ts
Normal file
@ -0,0 +1,187 @@
|
||||
import appImManager from "../../lib/appManagers/appImManager";
|
||||
import { $rootScope, cancelEvent, whichChild, findUpTag } from "../../lib/utils";
|
||||
import AppSearch, { SearchGroup } from "../appSearch";
|
||||
import PopupDatePicker from "../popupDatepicker";
|
||||
import { ripple } from "../ripple";
|
||||
import SearchInput from "../searchInput";
|
||||
|
||||
export class ChatSearch {
|
||||
private element: HTMLElement;
|
||||
private backBtn: HTMLElement;
|
||||
private searchInput: SearchInput;
|
||||
|
||||
private results: HTMLElement;
|
||||
|
||||
private footer: HTMLElement;
|
||||
private dateBtn: HTMLElement;
|
||||
private foundCountEl: HTMLElement;
|
||||
private controls: HTMLElement;
|
||||
private downBtn: HTMLElement;
|
||||
private upBtn: HTMLElement;
|
||||
|
||||
private appSearch: AppSearch;
|
||||
private searchGroup: SearchGroup;
|
||||
|
||||
private foundCount = 0;
|
||||
private selectedIndex = 0;
|
||||
private setPeerPromise: Promise<any>;
|
||||
|
||||
constructor() {
|
||||
this.element = document.createElement('div');
|
||||
this.element.classList.add('sidebar-header', 'chat-search', 'chats-container');
|
||||
|
||||
this.backBtn = document.createElement('button');
|
||||
this.backBtn.classList.add('btn-icon', 'tgico-back', 'sidebar-close-button');
|
||||
ripple(this.backBtn);
|
||||
|
||||
this.backBtn.addEventListener('click', () => {
|
||||
appImManager.topbar.classList.remove('hide-pinned');
|
||||
this.element.remove();
|
||||
this.searchInput.remove();
|
||||
this.results.remove();
|
||||
this.footer.remove();
|
||||
this.footer.removeEventListener('click', this.onFooterClick);
|
||||
this.dateBtn.removeEventListener('click', this.onDateClick);
|
||||
this.upBtn.removeEventListener('click', this.onUpClick);
|
||||
this.downBtn.removeEventListener('click', this.onDownClick);
|
||||
this.searchGroup.list.removeEventListener('click', this.onResultsClick);
|
||||
appImManager.bubblesContainer.classList.remove('search-results-active');
|
||||
}, {once: true});
|
||||
|
||||
this.searchInput = new SearchInput('Search');
|
||||
|
||||
// Results
|
||||
this.results = document.createElement('div');
|
||||
this.results.classList.add('chat-search-results', 'chats-container');
|
||||
|
||||
this.searchGroup = new SearchGroup('', 'messages', undefined, '', false);
|
||||
this.searchGroup.list.addEventListener('click', this.onResultsClick);
|
||||
|
||||
this.appSearch = new AppSearch(this.results, this.searchInput, {
|
||||
messages: this.searchGroup
|
||||
}, (count) => {
|
||||
this.foundCount = count;
|
||||
|
||||
if(!this.foundCount) {
|
||||
this.foundCountEl.innerText = this.searchInput.value ? 'No results' : '';
|
||||
this.results.classList.remove('active');
|
||||
appImManager.bubblesContainer.classList.remove('search-results-active');
|
||||
this.upBtn.setAttribute('disabled', 'true');
|
||||
this.downBtn.setAttribute('disabled', 'true');
|
||||
} else {
|
||||
this.selectResult(this.searchGroup.list.children[0] as HTMLElement);
|
||||
}
|
||||
});
|
||||
this.appSearch.beginSearch($rootScope.selectedPeerID);
|
||||
|
||||
//appImManager.topbar.parentElement.insertBefore(this.results, appImManager.bubblesContainer);
|
||||
appImManager.bubblesContainer.append(this.results);
|
||||
|
||||
// Footer
|
||||
this.footer = document.createElement('div');
|
||||
this.footer.classList.add('chat-search-footer');
|
||||
|
||||
this.footer.addEventListener('click', this.onFooterClick);
|
||||
ripple(this.footer);
|
||||
|
||||
this.foundCountEl = document.createElement('span');
|
||||
this.foundCountEl.classList.add('chat-search-count');
|
||||
|
||||
this.dateBtn = document.createElement('button');
|
||||
this.dateBtn.classList.add('btn-icon', 'tgico-calendar');
|
||||
|
||||
this.controls = document.createElement('div');
|
||||
this.controls.classList.add('chat-search-controls');
|
||||
|
||||
this.upBtn = document.createElement('button');
|
||||
this.upBtn.classList.add('btn-icon', 'tgico-up');
|
||||
this.downBtn = document.createElement('button');
|
||||
this.downBtn.classList.add('btn-icon', 'tgico-down');
|
||||
|
||||
this.upBtn.setAttribute('disabled', 'true');
|
||||
this.downBtn.setAttribute('disabled', 'true');
|
||||
|
||||
this.dateBtn.addEventListener('click', this.onDateClick);
|
||||
this.upBtn.addEventListener('click', this.onUpClick);
|
||||
this.downBtn.addEventListener('click', this.onDownClick);
|
||||
this.controls.append(this.upBtn, this.downBtn);
|
||||
|
||||
this.footer.append(this.foundCountEl, this.dateBtn, this.controls);
|
||||
|
||||
appImManager.topbar.parentElement.insertBefore(this.footer, appImManager.chatInput);
|
||||
|
||||
// Append container
|
||||
this.element.append(this.backBtn, this.searchInput.container);
|
||||
|
||||
appImManager.topbar.classList.add('hide-pinned');
|
||||
appImManager.topbar.parentElement.append(this.element);
|
||||
|
||||
this.searchInput.input.focus();
|
||||
}
|
||||
|
||||
onDateClick = (e: MouseEvent) => {
|
||||
cancelEvent(e);
|
||||
new PopupDatePicker(new Date(), appImManager.onDatePick).show();
|
||||
};
|
||||
|
||||
selectResult = (elem: HTMLElement) => {
|
||||
if(this.setPeerPromise) return this.setPeerPromise;
|
||||
|
||||
const peerID = +elem.getAttribute('data-peerID');
|
||||
const lastMsgID = +elem.dataset.mid || undefined;
|
||||
|
||||
const index = whichChild(elem);
|
||||
|
||||
if(index == (this.foundCount - 1)) {
|
||||
this.upBtn.setAttribute('disabled', 'true');
|
||||
} else {
|
||||
this.upBtn.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
if(!index) {
|
||||
this.downBtn.setAttribute('disabled', 'true');
|
||||
} else {
|
||||
this.downBtn.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
this.results.classList.remove('active');
|
||||
appImManager.bubblesContainer.classList.remove('search-results-active');
|
||||
|
||||
const res = appImManager.setPeer(peerID, lastMsgID);
|
||||
this.setPeerPromise = (res instanceof Promise ? res : Promise.resolve(res)).then(() => {
|
||||
this.selectedIndex = index;
|
||||
this.foundCountEl.innerText = `${index + 1} of ${this.foundCount}`;
|
||||
|
||||
const renderedCount = this.searchGroup.list.childElementCount;
|
||||
if(this.selectedIndex >= (renderedCount - 6)) {
|
||||
this.appSearch.searchMore();
|
||||
}
|
||||
}).finally(() => {
|
||||
this.setPeerPromise = null;
|
||||
});
|
||||
};
|
||||
|
||||
onResultsClick = (e: MouseEvent) => {
|
||||
const target = findUpTag(e.target, 'LI');
|
||||
if(target) {
|
||||
this.selectResult(target);
|
||||
}
|
||||
};
|
||||
|
||||
onFooterClick = (e: MouseEvent) => {
|
||||
if(this.foundCount) {
|
||||
appImManager.bubblesContainer.classList.toggle('search-results-active');
|
||||
this.results.classList.toggle('active');
|
||||
}
|
||||
};
|
||||
|
||||
onUpClick = (e: MouseEvent) => {
|
||||
cancelEvent(e);
|
||||
this.selectResult(this.searchGroup.list.children[this.selectedIndex + 1] as HTMLElement);
|
||||
};
|
||||
|
||||
onDownClick = (e: MouseEvent) => {
|
||||
cancelEvent(e);
|
||||
this.selectResult(this.searchGroup.list.children[this.selectedIndex - 1] as HTMLElement);
|
||||
};
|
||||
}
|
3
src/global.d.ts
vendored
3
src/global.d.ts
vendored
@ -5,6 +5,3 @@ declare module 'worker-loader!*' {
|
||||
|
||||
export default WebpackWorker;
|
||||
}
|
||||
|
||||
declare function setInterval(callback: (...args: any[]) => void, ms: number): number;
|
||||
declare function setTimeout(callback: (...args: any[]) => void, ms: number): number;
|
9
src/layer.d.ts
vendored
9
src/layer.d.ts
vendored
@ -1076,7 +1076,9 @@ export namespace Dialog {
|
||||
notify_settings: PeerNotifySettings,
|
||||
pts?: number,
|
||||
draft?: DraftMessage,
|
||||
folder_id?: number
|
||||
folder_id?: number,
|
||||
index?: number,
|
||||
peerID?: number
|
||||
};
|
||||
|
||||
export type dialogFolder = {
|
||||
@ -1091,7 +1093,10 @@ export namespace Dialog {
|
||||
unread_muted_peers_count: number,
|
||||
unread_unmuted_peers_count: number,
|
||||
unread_muted_messages_count: number,
|
||||
unread_unmuted_messages_count: number
|
||||
unread_unmuted_messages_count: number,
|
||||
index?: number,
|
||||
peerID?: number,
|
||||
folder_id?: number
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -733,7 +733,7 @@ export class AppDialogsManager {
|
||||
this.setListClickListener(ul, null, true);
|
||||
|
||||
if(!this.showFiltersTimeout) {
|
||||
this.showFiltersTimeout = setTimeout(() => {
|
||||
this.showFiltersTimeout = window.setTimeout(() => {
|
||||
this.showFiltersTimeout = 0;
|
||||
this.folders.menuScrollContainer.classList.remove('hide');
|
||||
this.setFiltersUnreadCount();
|
||||
@ -1086,7 +1086,7 @@ export class AppDialogsManager {
|
||||
|
||||
public accumulateArchivedUnread() {
|
||||
if(this.accumulateArchivedTimeout) return;
|
||||
this.accumulateArchivedTimeout = setTimeout(() => {
|
||||
this.accumulateArchivedTimeout = window.setTimeout(() => {
|
||||
this.accumulateArchivedTimeout = 0;
|
||||
const dialogs = appMessagesManager.dialogsStorage.getFolder(1);
|
||||
const sum = dialogs.reduce((acc, dialog) => acc + dialog.unread_count, 0);
|
||||
|
@ -14,10 +14,10 @@ import { logger, LogLevels } from "../logger";
|
||||
import appMediaViewer from "./appMediaViewer";
|
||||
import appSidebarLeft from "./appSidebarLeft";
|
||||
import appChatsManager, { Channel, Chat } from "./appChatsManager";
|
||||
import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply, wrapAlbum, wrapPoll, formatDate } from '../../components/wrappers';
|
||||
import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply, wrapAlbum, wrapPoll } from '../../components/wrappers';
|
||||
import ProgressivePreloader from '../../components/preloader';
|
||||
import { openBtnMenu, formatPhoneNumber, positionMenu, parseMenuButtonsTo, attachContextMenuListener } from '../../components/misc';
|
||||
import { ChatInput } from '../../components/chatInput';
|
||||
import { formatPhoneNumber, parseMenuButtonsTo } from '../../components/misc';
|
||||
import { ChatInput } from '../../components/chat/input';
|
||||
//import Scrollable from '../../components/scrollable';
|
||||
import Scrollable from '../../components/scrollable_new';
|
||||
import BubbleGroups from '../../components/bubbleGroups';
|
||||
@ -28,19 +28,18 @@ import appStickersManager from './appStickersManager';
|
||||
import AvatarElement from '../../components/avatar';
|
||||
import appInlineBotsManager from './AppInlineBotsManager';
|
||||
import StickyIntersector from '../../components/stickyIntersector';
|
||||
import { PopupButton, PopupPeer } from '../../components/popup';
|
||||
import { mediaSizes, touchSupport, isAndroid, isApple } from '../config';
|
||||
import animationIntersector from '../../components/animationIntersector';
|
||||
import PopupStickers from '../../components/popupStickers';
|
||||
import SearchInput from '../../components/searchInput';
|
||||
import AppSearch, { SearchGroup } from '../../components/appSearch';
|
||||
import PopupDatePicker from '../../components/popupDatepicker';
|
||||
import appMediaPlaybackController from '../../components/appMediaPlaybackController';
|
||||
import appPollsManager from './appPollsManager';
|
||||
import { ripple } from '../../components/ripple';
|
||||
import { horizontalMenu } from '../../components/horizontalMenu';
|
||||
import AudioElement from '../../components/audio';
|
||||
import { InputNotifyPeer, InputPeerNotifySettings } from '../../layer';
|
||||
import { ChatAudio } from '../../components/chat/audio';
|
||||
import { ChatContextMenu } from '../../components/chat/contextMenu';
|
||||
import { ChatSearch } from '../../components/chat/search';
|
||||
|
||||
//console.log('appImManager included33!');
|
||||
|
||||
@ -50,419 +49,6 @@ const testScroll = false;
|
||||
|
||||
const ANIMATIONGROUP = 'chat';
|
||||
|
||||
class ChatContextMenu {
|
||||
private element = document.getElementById('bubble-contextmenu') as HTMLDivElement;
|
||||
private buttons: {
|
||||
reply: HTMLButtonElement,
|
||||
edit: HTMLButtonElement,
|
||||
copy: HTMLButtonElement,
|
||||
pin: HTMLButtonElement,
|
||||
forward: HTMLButtonElement,
|
||||
delete: HTMLButtonElement
|
||||
} = {} as any;
|
||||
public msgID: number;
|
||||
|
||||
constructor(private attachTo: HTMLElement) {
|
||||
parseMenuButtonsTo(this.buttons, this.element.children);
|
||||
|
||||
attachContextMenuListener(attachTo, (e) => {
|
||||
let bubble: HTMLElement = null;
|
||||
|
||||
try {
|
||||
bubble = findUpClassName(e.target, 'bubble__container');
|
||||
} catch(e) {}
|
||||
|
||||
if(!bubble) return;
|
||||
|
||||
if(e instanceof MouseEvent) e.preventDefault();
|
||||
if(this.element.classList.contains('active')) {
|
||||
return false;
|
||||
}
|
||||
if(e instanceof MouseEvent) e.cancelBubble = true;
|
||||
|
||||
bubble = bubble.parentElement as HTMLDivElement; // bc container
|
||||
|
||||
let msgID = +bubble.dataset.mid;
|
||||
if(!msgID) return;
|
||||
|
||||
let peerID = $rootScope.selectedPeerID;
|
||||
this.msgID = msgID;
|
||||
|
||||
const message = appMessagesManager.getMessage(msgID);
|
||||
|
||||
this.buttons.copy.style.display = message.message ? '' : 'none';
|
||||
|
||||
if($rootScope.myID == peerID || (peerID < 0 && appChatsManager.hasRights(-peerID, 'pin'))) {
|
||||
this.buttons.pin.style.display = '';
|
||||
} else {
|
||||
this.buttons.pin.style.display = 'none';
|
||||
}
|
||||
|
||||
this.buttons.edit.style.display = appMessagesManager.canEditMessage(msgID) ? '' : 'none';
|
||||
|
||||
let side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right';
|
||||
positionMenu(e, this.element, side);
|
||||
openBtnMenu(this.element);
|
||||
|
||||
/////this.log('contextmenu', e, bubble, msgID, side);
|
||||
});
|
||||
|
||||
this.buttons.copy.addEventListener('click', () => {
|
||||
let message = appMessagesManager.getMessage(this.msgID);
|
||||
|
||||
let str = message ? message.message : '';
|
||||
|
||||
var textArea = document.createElement("textarea");
|
||||
textArea.value = str;
|
||||
textArea.style.position = "fixed"; //avoid scrolling to bottom
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
} catch (err) {
|
||||
console.error('Oops, unable to copy', err);
|
||||
}
|
||||
|
||||
document.body.removeChild(textArea);
|
||||
});
|
||||
|
||||
this.buttons.delete.addEventListener('click', () => {
|
||||
let peerID = $rootScope.selectedPeerID;
|
||||
let firstName = appPeersManager.getPeerTitle(peerID, false, true);
|
||||
|
||||
let callback = (revoke: boolean) => {
|
||||
appMessagesManager.deleteMessages([this.msgID], revoke);
|
||||
};
|
||||
|
||||
let title: string, description: string, buttons: PopupButton[];
|
||||
title = 'Delete Message?';
|
||||
description = `Are you sure you want to delete this message?`;
|
||||
|
||||
if(peerID == $rootScope.myID) {
|
||||
buttons = [{
|
||||
text: 'DELETE',
|
||||
isDanger: true,
|
||||
callback: () => callback(false)
|
||||
}];
|
||||
} else {
|
||||
buttons = [{
|
||||
text: 'DELETE JUST FOR ME',
|
||||
isDanger: true,
|
||||
callback: () => callback(false)
|
||||
}];
|
||||
|
||||
if(peerID > 0) {
|
||||
buttons.push({
|
||||
text: 'DELETE FOR ME AND ' + firstName,
|
||||
isDanger: true,
|
||||
callback: () => callback(true)
|
||||
});
|
||||
} else if(appChatsManager.hasRights(-peerID, 'deleteRevoke')) {
|
||||
buttons.push({
|
||||
text: 'DELETE FOR ALL',
|
||||
isDanger: true,
|
||||
callback: () => callback(true)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
buttons.push({
|
||||
text: 'CANCEL',
|
||||
isCancel: true
|
||||
});
|
||||
|
||||
let popup = new PopupPeer('popup-delete-chat', {
|
||||
peerID: peerID,
|
||||
title: title,
|
||||
description: description,
|
||||
buttons: buttons
|
||||
});
|
||||
|
||||
popup.show();
|
||||
});
|
||||
|
||||
this.buttons.reply.addEventListener('click', () => {
|
||||
const message = appMessagesManager.getMessage(this.msgID);
|
||||
const chatInputC = appImManager.chatInputC;
|
||||
chatInputC.setTopInfo(appPeersManager.getPeerTitle(message.fromID, true), message.message, undefined, message);
|
||||
chatInputC.replyToMsgID = this.msgID;
|
||||
chatInputC.editMsgID = 0;
|
||||
});
|
||||
|
||||
this.buttons.forward.addEventListener('click', () => {
|
||||
appForward.init([this.msgID]);
|
||||
});
|
||||
|
||||
this.buttons.edit.addEventListener('click', () => {
|
||||
const message = appMessagesManager.getMessage(this.msgID);
|
||||
const chatInputC = appImManager.chatInputC;
|
||||
chatInputC.setTopInfo('Editing', message.message, message.message, message);
|
||||
chatInputC.replyToMsgID = 0;
|
||||
chatInputC.editMsgID = this.msgID;
|
||||
});
|
||||
|
||||
this.buttons.pin.addEventListener('click', () => {
|
||||
appMessagesManager.updatePinnedMessage($rootScope.selectedPeerID, this.msgID);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ChatSearch {
|
||||
private element: HTMLElement;
|
||||
private backBtn: HTMLElement;
|
||||
private searchInput: SearchInput;
|
||||
|
||||
private results: HTMLElement;
|
||||
|
||||
private footer: HTMLElement;
|
||||
private dateBtn: HTMLElement;
|
||||
private foundCountEl: HTMLElement;
|
||||
private controls: HTMLElement;
|
||||
private downBtn: HTMLElement;
|
||||
private upBtn: HTMLElement;
|
||||
|
||||
private appSearch: AppSearch;
|
||||
private searchGroup: SearchGroup;
|
||||
|
||||
private foundCount = 0;
|
||||
private selectedIndex = 0;
|
||||
private setPeerPromise: Promise<any>;
|
||||
|
||||
constructor() {
|
||||
this.element = document.createElement('div');
|
||||
this.element.classList.add('sidebar-header', 'chat-search', 'chats-container');
|
||||
|
||||
this.backBtn = document.createElement('button');
|
||||
this.backBtn.classList.add('btn-icon', 'tgico-back', 'sidebar-close-button');
|
||||
ripple(this.backBtn);
|
||||
|
||||
this.backBtn.addEventListener('click', () => {
|
||||
appImManager.topbar.classList.remove('hide-pinned');
|
||||
this.element.remove();
|
||||
this.searchInput.remove();
|
||||
this.results.remove();
|
||||
this.footer.remove();
|
||||
this.footer.removeEventListener('click', this.onFooterClick);
|
||||
this.dateBtn.removeEventListener('click', this.onDateClick);
|
||||
this.upBtn.removeEventListener('click', this.onUpClick);
|
||||
this.downBtn.removeEventListener('click', this.onDownClick);
|
||||
this.searchGroup.list.removeEventListener('click', this.onResultsClick);
|
||||
appImManager.bubblesContainer.classList.remove('search-results-active');
|
||||
}, {once: true});
|
||||
|
||||
this.searchInput = new SearchInput('Search');
|
||||
|
||||
// Results
|
||||
this.results = document.createElement('div');
|
||||
this.results.classList.add('chat-search-results', 'chats-container');
|
||||
|
||||
this.searchGroup = new SearchGroup('', 'messages', undefined, '', false);
|
||||
this.searchGroup.list.addEventListener('click', this.onResultsClick);
|
||||
|
||||
this.appSearch = new AppSearch(this.results, this.searchInput, {
|
||||
messages: this.searchGroup
|
||||
}, (count) => {
|
||||
this.foundCount = count;
|
||||
|
||||
if(!this.foundCount) {
|
||||
this.foundCountEl.innerText = this.searchInput.value ? 'No results' : '';
|
||||
this.results.classList.remove('active');
|
||||
appImManager.bubblesContainer.classList.remove('search-results-active');
|
||||
this.upBtn.setAttribute('disabled', 'true');
|
||||
this.downBtn.setAttribute('disabled', 'true');
|
||||
} else {
|
||||
this.selectResult(this.searchGroup.list.children[0] as HTMLElement);
|
||||
}
|
||||
});
|
||||
this.appSearch.beginSearch($rootScope.selectedPeerID);
|
||||
|
||||
//appImManager.topbar.parentElement.insertBefore(this.results, appImManager.bubblesContainer);
|
||||
appImManager.bubblesContainer.append(this.results);
|
||||
|
||||
// Footer
|
||||
this.footer = document.createElement('div');
|
||||
this.footer.classList.add('chat-search-footer');
|
||||
|
||||
this.footer.addEventListener('click', this.onFooterClick);
|
||||
ripple(this.footer);
|
||||
|
||||
this.foundCountEl = document.createElement('span');
|
||||
this.foundCountEl.classList.add('chat-search-count');
|
||||
|
||||
this.dateBtn = document.createElement('button');
|
||||
this.dateBtn.classList.add('btn-icon', 'tgico-calendar');
|
||||
|
||||
this.controls = document.createElement('div');
|
||||
this.controls.classList.add('chat-search-controls');
|
||||
|
||||
this.upBtn = document.createElement('button');
|
||||
this.upBtn.classList.add('btn-icon', 'tgico-up');
|
||||
this.downBtn = document.createElement('button');
|
||||
this.downBtn.classList.add('btn-icon', 'tgico-down');
|
||||
|
||||
this.upBtn.setAttribute('disabled', 'true');
|
||||
this.downBtn.setAttribute('disabled', 'true');
|
||||
|
||||
this.dateBtn.addEventListener('click', this.onDateClick);
|
||||
this.upBtn.addEventListener('click', this.onUpClick);
|
||||
this.downBtn.addEventListener('click', this.onDownClick);
|
||||
this.controls.append(this.upBtn, this.downBtn);
|
||||
|
||||
this.footer.append(this.foundCountEl, this.dateBtn, this.controls);
|
||||
|
||||
appImManager.topbar.parentElement.insertBefore(this.footer, appImManager.chatInput);
|
||||
|
||||
// Append container
|
||||
this.element.append(this.backBtn, this.searchInput.container);
|
||||
|
||||
appImManager.topbar.classList.add('hide-pinned');
|
||||
appImManager.topbar.parentElement.append(this.element);
|
||||
|
||||
this.searchInput.input.focus();
|
||||
}
|
||||
|
||||
onDateClick = (e: MouseEvent) => {
|
||||
cancelEvent(e);
|
||||
new PopupDatePicker(new Date(), appImManager.onDatePick).show();
|
||||
};
|
||||
|
||||
selectResult = (elem: HTMLElement) => {
|
||||
if(this.setPeerPromise) return this.setPeerPromise;
|
||||
|
||||
const peerID = +elem.getAttribute('data-peerID');
|
||||
const lastMsgID = +elem.dataset.mid || undefined;
|
||||
|
||||
const index = whichChild(elem);
|
||||
|
||||
if(index == (this.foundCount - 1)) {
|
||||
this.upBtn.setAttribute('disabled', 'true');
|
||||
} else {
|
||||
this.upBtn.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
if(!index) {
|
||||
this.downBtn.setAttribute('disabled', 'true');
|
||||
} else {
|
||||
this.downBtn.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
this.results.classList.remove('active');
|
||||
appImManager.bubblesContainer.classList.remove('search-results-active');
|
||||
|
||||
const res = appImManager.setPeer(peerID, lastMsgID);
|
||||
this.setPeerPromise = (res instanceof Promise ? res : Promise.resolve(res)).then(() => {
|
||||
this.selectedIndex = index;
|
||||
this.foundCountEl.innerText = `${index + 1} of ${this.foundCount}`;
|
||||
|
||||
const renderedCount = this.searchGroup.list.childElementCount;
|
||||
if(this.selectedIndex >= (renderedCount - 6)) {
|
||||
this.appSearch.searchMore();
|
||||
}
|
||||
}).finally(() => {
|
||||
this.setPeerPromise = null;
|
||||
});
|
||||
};
|
||||
|
||||
onResultsClick = (e: MouseEvent) => {
|
||||
const target = findUpTag(e.target, 'LI');
|
||||
if(target) {
|
||||
this.selectResult(target);
|
||||
}
|
||||
};
|
||||
|
||||
onFooterClick = (e: MouseEvent) => {
|
||||
if(this.foundCount) {
|
||||
appImManager.bubblesContainer.classList.toggle('search-results-active');
|
||||
this.results.classList.toggle('active');
|
||||
}
|
||||
};
|
||||
|
||||
onUpClick = (e: MouseEvent) => {
|
||||
cancelEvent(e);
|
||||
this.selectResult(this.searchGroup.list.children[this.selectedIndex + 1] as HTMLElement);
|
||||
};
|
||||
|
||||
onDownClick = (e: MouseEvent) => {
|
||||
cancelEvent(e);
|
||||
this.selectResult(this.searchGroup.list.children[this.selectedIndex - 1] as HTMLElement);
|
||||
};
|
||||
}
|
||||
|
||||
class ChatAudio {
|
||||
public container: HTMLElement;
|
||||
private toggle: HTMLElement;
|
||||
private title: HTMLElement;
|
||||
private subtitle: HTMLElement;
|
||||
private close: HTMLElement;
|
||||
|
||||
constructor() {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('pinned-audio', 'pinned-container');
|
||||
this.container.style.display = 'none';
|
||||
|
||||
this.toggle = document.createElement('div');
|
||||
this.toggle.classList.add('pinned-audio-ico', 'tgico');
|
||||
|
||||
this.title = document.createElement('div');
|
||||
this.title.classList.add('pinned-audio-title');
|
||||
|
||||
this.subtitle = document.createElement('div');
|
||||
this.subtitle.classList.add('pinned-audio-subtitle');
|
||||
|
||||
this.close = document.createElement('button');
|
||||
this.close.classList.add('pinned-audio-close', 'btn-icon', 'tgico-close');
|
||||
|
||||
this.container.append(this.toggle, this.title, this.subtitle, this.close);
|
||||
|
||||
this.close.addEventListener('click', (e) => {
|
||||
cancelEvent(e);
|
||||
this.container.style.display = 'none';
|
||||
this.container.parentElement.classList.remove('is-audio-shown');
|
||||
if(this.toggle.classList.contains('flip-icon')) {
|
||||
appMediaPlaybackController.toggle();
|
||||
}
|
||||
});
|
||||
|
||||
this.toggle.addEventListener('click', (e) => {
|
||||
cancelEvent(e);
|
||||
appMediaPlaybackController.toggle();
|
||||
});
|
||||
|
||||
$rootScope.$on('audio_play', (e: CustomEvent) => {
|
||||
const {doc, mid} = e.detail;
|
||||
|
||||
let title: string, subtitle: string;
|
||||
if(doc.type == 'voice' || doc.type == 'round') {
|
||||
const message = appMessagesManager.getMessage(mid);
|
||||
title = appPeersManager.getPeerTitle(message.fromID, false, true);
|
||||
//subtitle = 'Voice message';
|
||||
subtitle = formatDate(message.date, false, false);
|
||||
} else {
|
||||
title = doc.audioTitle || doc.file_name;
|
||||
subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : 'Unknown Artist';
|
||||
}
|
||||
|
||||
this.title.innerHTML = title;
|
||||
this.subtitle.innerHTML = subtitle;
|
||||
this.toggle.classList.add('flip-icon');
|
||||
|
||||
this.container.dataset.mid = '' + mid;
|
||||
if(this.container.style.display) {
|
||||
const scrollTop = appImManager.scrollable.scrollTop;
|
||||
this.container.style.display = '';
|
||||
this.container.parentElement.classList.add('is-audio-shown');
|
||||
appImManager.scrollable.scrollTop = scrollTop;
|
||||
}
|
||||
});
|
||||
|
||||
$rootScope.$on('audio_pause', () => {
|
||||
this.toggle.classList.remove('flip-icon');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class AppImManager {
|
||||
public columnEl = document.getElementById('column-center') as HTMLDivElement;
|
||||
public btnJoin = this.columnEl.querySelector('.chat-join') as HTMLButtonElement;
|
||||
@ -651,14 +237,14 @@ export class AppImManager {
|
||||
if(message.media) {
|
||||
if(message.media.photo) {
|
||||
const photo = appPhotosManager.getPhoto(tempID);
|
||||
//if(photo._ != 'photoEmpty') {
|
||||
if(/* photo._ != 'photoEmpty' */photo) {
|
||||
const newPhoto = message.media.photo;
|
||||
newPhoto.downloaded = photo.downloaded;
|
||||
newPhoto.url = photo.url;
|
||||
//}
|
||||
}
|
||||
} else if(message.media.document) {
|
||||
const doc = appDocsManager.getDoc(tempID);
|
||||
if(/* doc._ != 'documentEmpty' && */doc.type && doc.type != 'sticker') {
|
||||
if(/* doc._ != 'documentEmpty' && */doc?.type && doc.type != 'sticker') {
|
||||
const newDoc = message.media.document;
|
||||
newDoc.downloaded = doc.downloaded;
|
||||
newDoc.url = doc.url;
|
||||
@ -1223,7 +809,7 @@ export class AppImManager {
|
||||
this.chatInner.classList.add('is-scrolling');
|
||||
}
|
||||
|
||||
this.isScrollingTimeout = setTimeout(() => {
|
||||
this.isScrollingTimeout = window.setTimeout(() => {
|
||||
this.chatInner.classList.remove('is-scrolling');
|
||||
this.isScrollingTimeout = 0;
|
||||
}, 1350);
|
||||
@ -1283,7 +869,7 @@ export class AppImManager {
|
||||
clearTimeout(this.isScrollingTimeout);
|
||||
}
|
||||
|
||||
this.isScrollingTimeout = setTimeout(() => {
|
||||
this.isScrollingTimeout = window.setTimeout(() => {
|
||||
this.chatInner.classList.remove('is-scrolling');
|
||||
this.isScrollingTimeout = 0;
|
||||
}, 1350);
|
||||
@ -3035,7 +2621,7 @@ export class AppImManager {
|
||||
}
|
||||
}
|
||||
|
||||
this.typingTimeouts[peerID] = setTimeout(() => {
|
||||
this.typingTimeouts[peerID] = window.setTimeout(() => {
|
||||
this.typingTimeouts[peerID] = 0;
|
||||
delete this.typingUsers[update.user_id];
|
||||
|
||||
|
@ -24,9 +24,10 @@ import { Modify } from "../../types";
|
||||
import { logger, LogLevels } from "../logger";
|
||||
import type {ApiFileManager} from '../mtproto/apiFileManager';
|
||||
import appDownloadManager from "./appDownloadManager";
|
||||
import { DialogFilter, InputDialogPeer, InputMessage, MethodDeclMap, MessagesFilter, PhotoSize } from "../../layer";
|
||||
import { DialogFilter, InputDialogPeer, InputMessage, MethodDeclMap, MessagesFilter, PhotoSize, DocumentAttribute, Dialog as MTDialog, MessagesDialogs, MessagesPeerDialogs } from "../../layer";
|
||||
|
||||
//console.trace('include');
|
||||
// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет
|
||||
|
||||
const APITIMEOUT = 0;
|
||||
|
||||
@ -47,27 +48,7 @@ export type HistoryResult = {
|
||||
unreadSkip: boolean
|
||||
};
|
||||
|
||||
export type Dialog = {
|
||||
_: 'dialog',
|
||||
top_message: number,
|
||||
read_inbox_max_id: number,
|
||||
read_outbox_max_id: number,
|
||||
peer: any,
|
||||
notify_settings: any,
|
||||
folder_id: number,
|
||||
flags: number,
|
||||
draft: any,
|
||||
unread_count: number,
|
||||
unread_mentions_count: number,
|
||||
|
||||
index: number,
|
||||
peerID: number,
|
||||
pFlags: Partial<{
|
||||
pinned: true,
|
||||
unread_mark: true
|
||||
}>,
|
||||
pts: number
|
||||
}
|
||||
export type Dialog = MTDialog.dialog;
|
||||
|
||||
export class DialogsStorage {
|
||||
public dialogs: {[peerID: string]: Dialog} = {};
|
||||
@ -487,7 +468,7 @@ export class AppMessagesManager {
|
||||
public pendingByRandomID: {[randomID: string]: [number, number]} = {};
|
||||
public pendingByMessageID: any = {};
|
||||
public pendingAfterMsgs: any = {};
|
||||
public pendingTopMsgs: any = {};
|
||||
public pendingTopMsgs: {[peerID: string]: number} = {};
|
||||
public sendFilePromise: CancellablePromise<void> = Promise.resolve();
|
||||
public tempID = -1;
|
||||
public tempFinalizeCallbacks: any = {};
|
||||
@ -1009,7 +990,7 @@ export class AppMessagesManager {
|
||||
attributes.push({_: 'documentAttributeFilename', file_name: fileName || apiFileName});
|
||||
|
||||
if(['document', 'video', 'audio', 'voice'].indexOf(attachType) !== -1 && !isDocument) {
|
||||
let doc: any = {
|
||||
let doc: MyDocument = {
|
||||
_: 'document',
|
||||
id: '' + messageID,
|
||||
duration: options.duration,
|
||||
@ -1021,7 +1002,7 @@ export class AppMessagesManager {
|
||||
mime_type: fileType,
|
||||
url: options.objectURL || '',
|
||||
size: file.size
|
||||
};
|
||||
} as any;
|
||||
|
||||
appDocsManager.saveDoc(doc);
|
||||
}
|
||||
@ -1297,21 +1278,18 @@ export class AppMessagesManager {
|
||||
|
||||
if(file.type.indexOf('video/') === 0) {
|
||||
let flags = 1;
|
||||
let videoAttribute = {
|
||||
let videoAttribute: DocumentAttribute.documentAttributeVideo = {
|
||||
_: 'documentAttributeVideo',
|
||||
flags: flags,
|
||||
pFlags: { // that's only for client, not going to telegram
|
||||
supports_streaming: true,
|
||||
round_message: false
|
||||
},
|
||||
round_message: false,
|
||||
supports_streaming: true,
|
||||
supports_streaming: true
|
||||
},
|
||||
duration: details.duration,
|
||||
w: details.width,
|
||||
h: details.height
|
||||
};
|
||||
|
||||
let doc: any = {
|
||||
let doc: MyDocument = {
|
||||
_: 'document',
|
||||
id: '' + messageID,
|
||||
attributes: [videoAttribute],
|
||||
@ -1320,7 +1298,7 @@ export class AppMessagesManager {
|
||||
mime_type: file.type,
|
||||
url: details.objectURL || '',
|
||||
size: file.size
|
||||
};
|
||||
} as any;
|
||||
|
||||
appDocsManager.saveDoc(doc);
|
||||
media.document = doc;
|
||||
@ -1894,9 +1872,11 @@ export class AppMessagesManager {
|
||||
hash: 0
|
||||
}, {
|
||||
timeout: APITIMEOUT
|
||||
}).then((dialogsResult: any) => {
|
||||
}).then((dialogsResult) => {
|
||||
///////this.log('messages.getDialogs result:', dialogsResult);
|
||||
|
||||
if(dialogsResult._ == 'messages.dialogsNotModified') return null;
|
||||
|
||||
if(!offsetDate) {
|
||||
telegramMeWebService.setAuthorized(true);
|
||||
}
|
||||
@ -1905,21 +1885,31 @@ export class AppMessagesManager {
|
||||
appChatsManager.saveApiChats(dialogsResult.chats);
|
||||
this.saveMessages(dialogsResult.messages);
|
||||
|
||||
var maxSeenIdIncremented = offsetDate ? true : false;
|
||||
var hasPrepend = false;
|
||||
let length = dialogsResult.dialogs.length;
|
||||
let noIDsDialogs: any = {};
|
||||
for(let i = length - 1; i >= 0; --i) {
|
||||
let dialog = dialogsResult.dialogs[i];
|
||||
let maxSeenIdIncremented = offsetDate ? true : false;
|
||||
let hasPrepend = false;
|
||||
let noIDsDialogs: {[peerID: number]: Dialog} = {};
|
||||
(dialogsResult.dialogs as Dialog[]).forEachReverse(dialog => {
|
||||
//const d = Object.assign({}, dialog);
|
||||
// ! нужно передавать folderID, так как по папке != 0 нет свойства folder_id
|
||||
this.saveConversation(dialog, folderID);
|
||||
|
||||
/* if(dialog.peerID == 239602833) {
|
||||
this.log.error('lun bot', folderID, d);
|
||||
} */
|
||||
|
||||
this.saveConversation(dialog);
|
||||
if(offsetIndex && dialog.index > offsetIndex) {
|
||||
this.newDialogsToHandle[dialog.peerID] = dialog;
|
||||
hasPrepend = true;
|
||||
}
|
||||
|
||||
// ! это может случиться, если запрос идёт не по папке 0, а по 1. почему-то read'ов нет
|
||||
// ! в итоге, чтобы получить 1 диалог, делается первый запрос по папке 0, потом запрос для архивных по папке 1, и потом ещё перезагрузка архивного диалога
|
||||
if(!dialog.read_inbox_max_id && !dialog.read_outbox_max_id) {
|
||||
noIDsDialogs[dialog.peerID] = dialog;
|
||||
|
||||
/* if(dialog.peerID == 239602833) {
|
||||
this.log.error('lun bot', folderID);
|
||||
} */
|
||||
}
|
||||
|
||||
if(!maxSeenIdIncremented &&
|
||||
@ -1927,7 +1917,7 @@ export class AppMessagesManager {
|
||||
this.incrementMaxSeenID(dialog.top_message);
|
||||
maxSeenIdIncremented = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(Object.keys(noIDsDialogs).length) {
|
||||
//setTimeout(() => { // test bad situation
|
||||
@ -1941,9 +1931,11 @@ export class AppMessagesManager {
|
||||
//}, 10e3);
|
||||
}
|
||||
|
||||
const count = (dialogsResult as MessagesDialogs.messagesDialogsSlice).count;
|
||||
|
||||
if(!dialogsResult.dialogs.length ||
|
||||
!dialogsResult.count ||
|
||||
dialogs.length >= dialogsResult.count) {
|
||||
!count ||
|
||||
dialogs.length >= count) {
|
||||
this.dialogsStorage.allDialogsLoaded[folderID] = true;
|
||||
}
|
||||
|
||||
@ -1953,7 +1945,7 @@ export class AppMessagesManager {
|
||||
$rootScope.$broadcast('dialogs_multiupdate', {});
|
||||
}
|
||||
|
||||
return dialogsResult.count;
|
||||
return count;
|
||||
});
|
||||
}
|
||||
|
||||
@ -2115,11 +2107,11 @@ export class AppMessagesManager {
|
||||
}
|
||||
|
||||
if(justClear) {
|
||||
$rootScope.$broadcast('dialog_flush', {peerID: peerID});
|
||||
$rootScope.$broadcast('dialog_flush', {peerID});
|
||||
} else {
|
||||
this.dialogsStorage.dropDialog(peerID);
|
||||
|
||||
$rootScope.$broadcast('dialog_drop', {peerID: peerID});
|
||||
$rootScope.$broadcast('dialog_drop', {peerID});
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -2598,7 +2590,9 @@ export class AppMessagesManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
public applyConversations(dialogsResult: any) {
|
||||
public applyConversations(dialogsResult: MessagesPeerDialogs.messagesPeerDialogs) {
|
||||
// * В эту функцию попадут только те диалоги, в которых есть read_inbox_max_id и read_outbox_max_id, в отличие от тех, что будут в getTopMessages
|
||||
|
||||
appUsersManager.saveApiUsers(dialogsResult.users);
|
||||
appChatsManager.saveApiChats(dialogsResult.chats);
|
||||
this.saveMessages(dialogsResult.messages);
|
||||
@ -2607,27 +2601,33 @@ export class AppMessagesManager {
|
||||
|
||||
const updatedDialogs: {[peerID: number]: Dialog} = {};
|
||||
let hasUpdated = false;
|
||||
dialogsResult.dialogs.forEach((dialog: any) => {
|
||||
(dialogsResult.dialogs as Dialog[]).forEach((dialog) => {
|
||||
const peerID = appPeersManager.getPeerID(dialog.peer);
|
||||
let topMessage = dialog.top_message;
|
||||
const topPendingMesage = this.pendingTopMsgs[peerID];
|
||||
if(topPendingMesage) {
|
||||
if(!topMessage || this.getMessage(topPendingMesage).date > this.getMessage(topMessage).date) {
|
||||
dialog.top_message = topMessage = topPendingMesage;
|
||||
const topPendingMessage = this.pendingTopMsgs[peerID];
|
||||
if(topPendingMessage) {
|
||||
if(!topMessage || this.getMessage(topPendingMessage).date > this.getMessage(topMessage).date) {
|
||||
dialog.top_message = topMessage = topPendingMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/* const d = Object.assign({}, dialog);
|
||||
if(peerID == 239602833) {
|
||||
this.log.error('applyConversation lun', dialog, d);
|
||||
} */
|
||||
|
||||
if(topMessage) {
|
||||
const wasDialogBefore = this.getDialogByPeerID(peerID)[0];
|
||||
|
||||
// here need to just replace, not FULL replace dialog! WARNING
|
||||
if(wasDialogBefore && wasDialogBefore.pFlags && wasDialogBefore.pFlags.pinned) {
|
||||
/* if(wasDialogBefore?.pFlags?.pinned && !dialog?.pFlags?.pinned) {
|
||||
this.log.error('here need to just replace, not FULL replace dialog! WARNING', wasDialogBefore, dialog);
|
||||
if(!dialog.pFlags) dialog.pFlags = {};
|
||||
dialog.pFlags.pinned = true;
|
||||
}
|
||||
} */
|
||||
|
||||
this.saveConversation(dialog);
|
||||
|
||||
|
||||
if(wasDialogBefore) {
|
||||
$rootScope.$broadcast('dialog_top', dialog);
|
||||
} else {
|
||||
@ -2656,11 +2656,16 @@ export class AppMessagesManager {
|
||||
}
|
||||
}
|
||||
|
||||
public saveConversation(dialog: Dialog) {
|
||||
public saveConversation(dialog: Dialog, folderID = 0) {
|
||||
const peerID = appPeersManager.getPeerID(dialog.peer);
|
||||
if(!peerID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(dialog._ != 'dialog'/* || peerID == 239602833 */) {
|
||||
console.error('saveConversation not regular dialog', dialog, Object.assign({}, dialog));
|
||||
}
|
||||
|
||||
const channelID = appPeersManager.isChannel(peerID) ? -peerID : 0;
|
||||
const peerText = appPeersManager.getPeerSearchText(peerID);
|
||||
searchIndexManager.indexObject(peerID, peerText, this.dialogsIndex);
|
||||
@ -2700,7 +2705,14 @@ export class AppMessagesManager {
|
||||
dialog.read_inbox_max_id = appMessagesIDsManager.getFullMessageID(dialog.read_inbox_max_id, channelID);
|
||||
dialog.read_outbox_max_id = appMessagesIDsManager.getFullMessageID(dialog.read_outbox_max_id, channelID);
|
||||
|
||||
if(!dialog.hasOwnProperty('folder_id')) dialog.folder_id = 0;
|
||||
if(!dialog.hasOwnProperty('folder_id')) {
|
||||
if(dialog._ == 'dialog') {
|
||||
dialog.folder_id = folderID;
|
||||
}/* else if(dialog._ == 'dialogFolder') {
|
||||
dialog.folder_id = dialog.folder.id;
|
||||
} */
|
||||
}
|
||||
|
||||
dialog.peerID = peerID;
|
||||
|
||||
this.dialogsStorage.generateIndexForDialog(dialog);
|
||||
@ -3057,7 +3069,7 @@ export class AppMessagesManager {
|
||||
this.incrementMaxSeenID(newMaxSeenID);
|
||||
}
|
||||
|
||||
$rootScope.$broadcast('dialogs_multiupdate', this.newDialogsToHandle);
|
||||
$rootScope.$broadcast('dialogs_multiupdate', this.newDialogsToHandle as any);
|
||||
this.newDialogsToHandle = {};
|
||||
};
|
||||
|
||||
@ -3502,7 +3514,7 @@ export class AppMessagesManager {
|
||||
if(!update.order) {
|
||||
apiManager.invokeApi('messages.getPinnedDialogs', {
|
||||
folder_id: folderID
|
||||
}).then((dialogsResult: any) => {
|
||||
}).then((dialogsResult) => {
|
||||
dialogsResult.dialogs.reverse();
|
||||
this.applyConversations(dialogsResult);
|
||||
|
||||
@ -3750,8 +3762,9 @@ export class AppMessagesManager {
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(historiesUpdated).forEach(peerID => {
|
||||
let updatedData = historiesUpdated[+peerID];
|
||||
Object.keys(historiesUpdated).forEach(_peerID => {
|
||||
const peerID = +_peerID;
|
||||
let updatedData = historiesUpdated[peerID];
|
||||
let historyStorage = this.historiesStorage[peerID];
|
||||
if(historyStorage !== undefined) {
|
||||
let newHistory: number[] = [];
|
||||
@ -3778,22 +3791,22 @@ export class AppMessagesManager {
|
||||
}
|
||||
historyStorage.pending = newPending;
|
||||
|
||||
$rootScope.$broadcast('history_delete', {peerID: peerID, msgs: updatedData.msgs});
|
||||
$rootScope.$broadcast('history_delete', {peerID, msgs: updatedData.msgs});
|
||||
}
|
||||
|
||||
let foundDialog = this.getDialogByPeerID(+peerID)[0];
|
||||
let foundDialog = this.getDialogByPeerID(peerID)[0];
|
||||
if(foundDialog) {
|
||||
if(updatedData.unread) {
|
||||
foundDialog.unread_count -= updatedData.unread;
|
||||
|
||||
$rootScope.$broadcast('dialog_unread', {
|
||||
peerID: peerID,
|
||||
peerID,
|
||||
count: foundDialog.unread_count
|
||||
});
|
||||
}
|
||||
|
||||
if(updatedData.msgs[foundDialog.top_message]) {
|
||||
this.reloadConversation(+peerID);
|
||||
this.reloadConversation(peerID);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ import appUsersManager from "./appUsersManager";
|
||||
import appChatsManager from "./appChatsManager";
|
||||
import { isObject } from "../utils";
|
||||
import { RichTextProcessor } from "../richtextprocessor";
|
||||
import { InputPeer, InputDialogPeer } from "../../layer";
|
||||
import { InputPeer, InputDialogPeer, Peer } from "../../layer";
|
||||
|
||||
// https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC
|
||||
/*
|
||||
@ -20,30 +20,30 @@ const DialogColorsFg = ['#c03d33', '#4fad2d', '#d09306', '#168acd', '#8544d6', '
|
||||
const DialogColors = ['#e17076', '#7bc862', '#e5ca77', '#65AADD', '#a695e7', '#ee7aae', '#6ec9cb', '#faa774'];
|
||||
const DialogColorsMap = [0, 7, 4, 1, 6, 3, 5];
|
||||
|
||||
const AppPeersManager = {
|
||||
getPeerPhoto: (peerID: number) => {
|
||||
export class AppPeersManager {
|
||||
public getPeerPhoto(peerID: number) {
|
||||
return peerID > 0
|
||||
? appUsersManager.getUserPhoto(peerID)
|
||||
: appChatsManager.getChatPhoto(-peerID);
|
||||
},
|
||||
}
|
||||
|
||||
getPeerMigratedTo: (peerID: number) => {
|
||||
public getPeerMigratedTo(peerID: number) {
|
||||
if(peerID >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let chat = appChatsManager.getChat(-peerID);
|
||||
if(chat && chat.migrated_to && chat.pFlags.deactivated) {
|
||||
return AppPeersManager.getPeerID(chat.migrated_to);
|
||||
return this.getPeerID(chat.migrated_to);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
getPeerTitle: (peerID: number | any, plainText = false, onlyFirstName = false) => {
|
||||
public getPeerTitle(peerID: number | any, plainText = false, onlyFirstName = false) {
|
||||
let peer: any = {};
|
||||
if(!isObject(peerID)) {
|
||||
peer = AppPeersManager.getPeer(peerID);
|
||||
peer = this.getPeer(peerID);
|
||||
} else peer = peerID;
|
||||
|
||||
let title = '';
|
||||
@ -62,9 +62,9 @@ const AppPeersManager = {
|
||||
}
|
||||
|
||||
return plainText ? title : RichTextProcessor.wrapEmojiText(title);
|
||||
},
|
||||
}
|
||||
|
||||
getOutputPeer: (peerID: number) => {
|
||||
public getOutputPeer(peerID: number): Peer {
|
||||
if(peerID > 0) {
|
||||
return {_: 'peerUser', user_id: peerID};
|
||||
}
|
||||
@ -75,29 +75,29 @@ const AppPeersManager = {
|
||||
}
|
||||
|
||||
return {_: 'peerChat', chat_id: chatID};
|
||||
},
|
||||
}
|
||||
|
||||
getPeerString: (peerID: number) => {
|
||||
public getPeerString(peerID: number) {
|
||||
if(peerID > 0) {
|
||||
return appUsersManager.getUserString(peerID);
|
||||
}
|
||||
return appChatsManager.getChatString(-peerID);
|
||||
},
|
||||
}
|
||||
|
||||
getPeerUsername: (peerID: number): string => {
|
||||
public getPeerUsername(peerID: number): string {
|
||||
if(peerID > 0) {
|
||||
return appUsersManager.getUser(peerID).username || '';
|
||||
}
|
||||
return appChatsManager.getChat(-peerID).username || '';
|
||||
},
|
||||
}
|
||||
|
||||
getPeer: (peerID: number) => {
|
||||
public getPeer(peerID: number) {
|
||||
return peerID > 0
|
||||
? appUsersManager.getUser(peerID)
|
||||
: appChatsManager.getChat(-peerID)
|
||||
},
|
||||
}
|
||||
|
||||
getPeerID: (peerString: any): number => {
|
||||
public getPeerID(peerString: any): number {
|
||||
if(typeof(peerString) === 'number') return peerString;
|
||||
else if(isObject(peerString)) {
|
||||
return peerString.user_id
|
||||
@ -108,29 +108,29 @@ const AppPeersManager = {
|
||||
const peerParams = peerString.substr(1).split('_');
|
||||
|
||||
return isUser ? peerParams[0] : -peerParams[0] || 0;
|
||||
},
|
||||
}
|
||||
|
||||
isChannel: (peerID: number): boolean => {
|
||||
public isChannel(peerID: number): boolean {
|
||||
return (peerID < 0) && appChatsManager.isChannel(-peerID);
|
||||
},
|
||||
}
|
||||
|
||||
isMegagroup: (peerID: number) => {
|
||||
public isMegagroup(peerID: number) {
|
||||
return (peerID < 0) && appChatsManager.isMegagroup(-peerID);
|
||||
},
|
||||
}
|
||||
|
||||
isAnyGroup: (peerID: number): boolean => {
|
||||
public isAnyGroup(peerID: number): boolean {
|
||||
return (peerID < 0) && !appChatsManager.isBroadcast(-peerID);
|
||||
},
|
||||
}
|
||||
|
||||
isBroadcast: (id: number): boolean => {
|
||||
return AppPeersManager.isChannel(id) && !AppPeersManager.isMegagroup(id);
|
||||
},
|
||||
public isBroadcast(id: number): boolean {
|
||||
return this.isChannel(id) && !this.isMegagroup(id);
|
||||
}
|
||||
|
||||
isBot: (peerID: number): boolean => {
|
||||
public isBot(peerID: number): boolean {
|
||||
return (peerID > 0) && appUsersManager.isBot(peerID);
|
||||
},
|
||||
}
|
||||
|
||||
getInputPeer: (peerString: string): any => {
|
||||
public getInputPeer(peerString: string): InputPeer {
|
||||
var firstChar = peerString.charAt(0);
|
||||
var peerParams = peerString.substr(1).split('_');
|
||||
let id = +peerParams[0];
|
||||
@ -152,7 +152,7 @@ const AppPeersManager = {
|
||||
return {
|
||||
_: 'inputPeerChannel',
|
||||
channel_id: id,
|
||||
access_hash: peerParams[1] || 0
|
||||
access_hash: peerParams[1] || '0'
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
@ -160,9 +160,9 @@ const AppPeersManager = {
|
||||
chat_id: id
|
||||
};
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
getInputPeerByID: (peerID: number): InputPeer => {
|
||||
public getInputPeerByID(peerID: number): InputPeer {
|
||||
if(!peerID) {
|
||||
return {_: 'inputPeerEmpty'};
|
||||
}
|
||||
@ -181,22 +181,22 @@ const AppPeersManager = {
|
||||
user_id: peerID,
|
||||
access_hash: appUsersManager.getUser(peerID).access_hash
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
getInputDialogPeerByID: (peerID: number): InputDialogPeer => {
|
||||
public getInputDialogPeerByID(peerID: number): InputDialogPeer {
|
||||
return {
|
||||
_: 'inputDialogPeer',
|
||||
peer: AppPeersManager.getInputPeerByID(peerID)
|
||||
peer: this.getInputPeerByID(peerID)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
getPeerColorByID: (peerID: number, pic = true) => {
|
||||
public getPeerColorByID(peerID: number, pic = true) {
|
||||
const idx = DialogColorsMap[(peerID < 0 ? -peerID : peerID) % 7];
|
||||
const color = (pic ? DialogColors : DialogColorsFg)[idx];
|
||||
return color;
|
||||
},
|
||||
}
|
||||
|
||||
getPeerSearchText: (peerID: number) => {
|
||||
public getPeerSearchText(peerID: number) {
|
||||
let text;
|
||||
if(peerID > 0) {
|
||||
text = '%pu ' + appUsersManager.getUserSearchText(peerID);
|
||||
@ -206,6 +206,7 @@ const AppPeersManager = {
|
||||
}
|
||||
return text;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default AppPeersManager;
|
||||
const appPeersManager = new AppPeersManager();
|
||||
export default appPeersManager;
|
||||
|
@ -228,7 +228,7 @@ export class AppPhotosManager {
|
||||
const photo = this.getPhoto(photoID);
|
||||
|
||||
// @ts-ignore
|
||||
if(photo._ == 'photoEmpty') {
|
||||
if(!photo || photo._ == 'photoEmpty') {
|
||||
throw new Error('preloadPhoto photoEmpty!');
|
||||
}
|
||||
|
||||
|
@ -416,7 +416,7 @@ export class AppSidebarRight extends SidebarSlider {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
public async performSearchResult(messages: any[], type: string) {
|
||||
public async performSearchResult(messages: any[], type: SharedMediaType) {
|
||||
const peerID = this.peerID;
|
||||
const elemsToAppend: HTMLElement[] = [];
|
||||
const promises: Promise<any>[] = [];
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Dialog } from "./appManagers/appMessagesManager";
|
||||
/*!
|
||||
* Webogram v0.7.0 - messaging web application for MTProto
|
||||
* https://github.com/zhukov/webogram
|
||||
@ -156,29 +157,36 @@ type BroadcastEvents = {
|
||||
'user_update': any,
|
||||
'user_auth': any,
|
||||
'peer_changed': any,
|
||||
|
||||
'filter_delete': any,
|
||||
'filter_update': any,
|
||||
'message_edit': any,
|
||||
|
||||
'dialog_draft': any,
|
||||
'messages_pending': any,
|
||||
'dialog_unread': {peerID: number, count?: number},
|
||||
'dialog_flush': {peerID: number},
|
||||
'dialog_drop': {peerID: number, dialog?: Dialog},
|
||||
'dialog_migrate': any,
|
||||
'dialog_top': Dialog,
|
||||
'dialog_notify_settings': number,
|
||||
'dialogs_multiupdate': {[peerID: string]: Dialog},
|
||||
'dialogs_archived_unread': any,
|
||||
|
||||
'history_append': any,
|
||||
'history_update': any,
|
||||
'dialogs_multiupdate': any,
|
||||
'dialog_unread': any,
|
||||
'dialog_flush': any,
|
||||
'dialog_drop': any,
|
||||
'dialog_migrate': any,
|
||||
'dialog_top': any,
|
||||
'history_reply_markup': any,
|
||||
'history_multiappend': any,
|
||||
'messages_read': any,
|
||||
'history_delete': any,
|
||||
'history_forbidden': any,
|
||||
'history_reload': any,
|
||||
'history_delete': {peerID: number, msgs: {[mid: number]: true}},
|
||||
'history_forbidden': number,
|
||||
'history_reload': number,
|
||||
'history_request': any,
|
||||
|
||||
'message_edit': any,
|
||||
'message_views': any,
|
||||
'message_sent': any,
|
||||
'history_request': any,
|
||||
'messages_pending': void,
|
||||
'messages_read': any,
|
||||
'messages_downloaded': any,
|
||||
|
||||
'contacts_update': any,
|
||||
'avatar_update': any,
|
||||
'stickers_installed': any,
|
||||
@ -186,7 +194,6 @@ type BroadcastEvents = {
|
||||
'chat_full_update': any,
|
||||
'peer_pinned_message': any,
|
||||
'poll_update': any,
|
||||
'dialogs_archived_unread': any,
|
||||
'audio_play': any,
|
||||
'audio_pause': any,
|
||||
'chat_update': any,
|
||||
@ -195,7 +202,6 @@ type BroadcastEvents = {
|
||||
'channel_settings': any,
|
||||
'webpage_updated': any,
|
||||
'draft_updated': any,
|
||||
'dialog_notify_settings': number,
|
||||
};
|
||||
|
||||
export const $rootScope = {
|
||||
|
@ -41,4 +41,17 @@
|
||||
"params": [
|
||||
{"name": "url", "type": "string"}
|
||||
]
|
||||
}, {
|
||||
"predicate": "dialog",
|
||||
"params": [
|
||||
{"name": "index", "type": "number"},
|
||||
{"name": "peerID", "type": "number"}
|
||||
]
|
||||
}, {
|
||||
"predicate": "dialogFolder",
|
||||
"params": [
|
||||
{"name": "index", "type": "number"},
|
||||
{"name": "peerID", "type": "number"},
|
||||
{"name": "folder_id", "type": "number"}
|
||||
]
|
||||
}]
|
@ -21,7 +21,7 @@
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
//"importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
"isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
@ -30,6 +30,7 @@
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
"strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */
|
||||
// "skipLibCheck": true,
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
@ -40,7 +41,7 @@
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
@ -66,6 +67,7 @@
|
||||
"./public/recorder.min.js",
|
||||
"public",
|
||||
"coverage",
|
||||
"./src/scripts",
|
||||
"./public/*.js",
|
||||
"./src/lib/crypto/crypto.worker.js",
|
||||
"./src/vendor/StackBlur.js",
|
||||
|
Loading…
x
Reference in New Issue
Block a user