MTProto autocomplete flags

Chat context menu fixes
Revote & stop poll from context menu
This commit is contained in:
morethanwords 2020-10-10 01:36:06 +03:00
parent a53581c3f0
commit bc4c892880
22 changed files with 534 additions and 530 deletions

View File

@ -0,0 +1,30 @@
import { ripple } from "./ripple";
export type ButtonMenuItemOptions = {icon: string, text: string, onClick: () => void, element?: HTMLElement};
const ButtonMenuItem = (options: ButtonMenuItemOptions) => {
if(options.element) return options.element;
const {icon, text, onClick} = options;
const el = document.createElement('div');
el.className = 'btn-menu-item tgico-' + icon;
el.innerText = text;
ripple(el);
el.addEventListener('click', onClick);
return options.element = el;
};
const ButtonMenu = (buttons: ButtonMenuItemOptions[]) => {
const el = document.createElement('div');
el.classList.add('btn-menu');
const items = buttons.map(ButtonMenuItem);
el.append(...items);
return el;
};
export default ButtonMenu;

View File

@ -2,28 +2,26 @@ 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 appPollsManager from "../../lib/appManagers/appPollsManager";
import $rootScope from "../../lib/rootScope";
import { findUpClassName } from "../../lib/utils";
import { attachContextMenuListener, openBtnMenu, parseMenuButtonsTo, positionMenu } from "../misc";
import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu";
import { attachContextMenuListener, openBtnMenu, positionMenu } from "../misc";
import { PopupButton, PopupPeer } from "../popup";
import appSidebarRight from "../sidebarRight";
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;
private buttons: (ButtonMenuItemOptions & {verify: (peerID: number, msgID: number) => boolean})[];
private element: HTMLElement;
public msgID: number;
constructor(private attachTo: HTMLElement) {
parseMenuButtonsTo(this.buttons, this.element.children);
attachContextMenuListener(attachTo, (e) => {
if(this.init) {
this.init();
this.init = null;
}
let bubble: HTMLElement = null;
try {
@ -40,126 +38,186 @@ export class ChatContextMenu {
bubble = bubble.parentElement as HTMLDivElement; // bc container
let msgID = +bubble.dataset.mid;
const msgID = +bubble.dataset.mid;
if(!msgID) return;
let peerID = $rootScope.selectedPeerID;
const peerID = $rootScope.selectedPeerID;
this.msgID = msgID;
const message = appMessagesManager.getMessage(msgID);
this.buttons.forEach(button => {
const good = button.verify(peerID, msgID);
button.element.classList.toggle('hide', !good);
});
this.buttons.copy.style.display = message.message ? '' : 'none';
this.buttons.pin.classList.toggle('hide', peerID < 0 && !appChatsManager.hasRights(-peerID, 'pin'));
this.buttons.edit.style.display = appMessagesManager.canEditMessage(msgID) ? '' : 'none';
this.buttons.reply.classList.toggle('hide', peerID < 0 && !appChatsManager.hasRights(-peerID, 'send'));
this.buttons.delete.classList.toggle('hide', peerID < 0 && appPeersManager.isBroadcast(peerID) && !appChatsManager.hasRights(-peerID, 'deleteRevoke'));
let side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right';
const 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', () => {
appSidebarRight.forwardTab.open([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);
});
}
private init = () => {
this.buttons = [{
icon: 'reply',
text: 'Reply',
onClick: this.onReplyClick,
verify: (peerID: number) => peerID > 0 || appChatsManager.hasRights(-peerID, 'send')
}, {
icon: 'edit',
text: 'Edit',
onClick: this.onEditClick,
verify: (peerID: number, msgID: number) => appMessagesManager.canEditMessage(msgID)
}, {
icon: 'copy',
text: 'Copy',
onClick: this.onCopyClick,
verify: (peerID: number, msgID: number) => !!appMessagesManager.getMessage(msgID).message
}, {
icon: 'pin',
text: 'Pin',
onClick: this.onPinClick,
verify: (peerID: number) => peerID == $rootScope.myID || (peerID < 0 && appChatsManager.hasRights(-peerID, 'pin'))
}, {
icon: 'revote',
text: 'Revote',
onClick: this.onRetractVote,
verify: (peerID: number, msgID) => {
const message = appMessagesManager.getMessage(msgID);
const poll = message.media?.poll;
return poll && !poll.pFlags.closed;
}
}, {
icon: 'lock',
text: 'Stop poll',
onClick: this.onStopPoll,
verify: (peerID: number, msgID) => {
const message = appMessagesManager.getMessage(msgID);
const poll = message.media?.poll;
return appMessagesManager.canEditMessage(msgID) && message.fromID == $rootScope.myID && message.fwd_from === undefined && poll && !poll.pFlags.closed;
}
}, {
icon: 'forward',
text: 'Forward',
onClick: this.onForwardClick,
verify: () => true
}, {
icon: 'delete danger',
text: 'Delete',
onClick: this.onDeleteClick,
verify: (peerID: number, msgID: number) => peerID > 0 || appMessagesManager.getMessage(msgID).fromID == $rootScope.myID || appChatsManager.hasRights(-peerID, 'deleteRevoke')
}];
this.element = ButtonMenu(this.buttons);
this.element.id = 'bubble-contextmenu';
appImManager.chatInput.parentElement.insertBefore(this.element, appImManager.chatInput);
};
private onReplyClick = () => {
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;
};
private onEditClick = () => {
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;
};
private onCopyClick = () => {
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);
};
private onPinClick = () => {
appMessagesManager.updatePinnedMessage($rootScope.selectedPeerID, this.msgID);
};
private onRetractVote = () => {
appPollsManager.sendVote(this.msgID, []);
};
private onStopPoll = () => {
appPollsManager.stopPoll(this.msgID);
};
private onForwardClick = () => {
appSidebarRight.forwardTab.open([this.msgID]);
};
private onDeleteClick = () => {
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();
};
}

View File

@ -1,20 +1,20 @@
import Scrollable from "../scrollable";
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 { isTouchSupported } from "../../helpers/touchSupport";
import appDocsManager from "../../lib/appManagers/appDocsManager";
import appImManager from "../../lib/appManagers/appImManager";
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
import appWebPagesManager from "../../lib/appManagers/appWebPagesManager";
import apiManager from "../../lib/mtproto/mtprotoworker";
//import Recorder from '../opus-recorder/dist/recorder.min';
import opusDecodeController from "../../lib/opusDecodeController";
import appDocsManager from "../../lib/appManagers/appDocsManager";
import { RichTextProcessor } from "../../lib/richtextprocessor";
import { calcImageInBox, cancelEvent, getRichValue } from "../../lib/utils";
import emoticonsDropdown from "../emoticonsDropdown";
import { Layouter, RectPart } from "../groupedLayout";
import PopupCreatePoll from "../popupCreatePoll";
import Scrollable from "../scrollable";
import { toast } from "../toast";
import { isTouchSupported } from "../../helpers/touchSupport";
import { wrapDocument, wrapReply } from "../wrappers";
const RECORD_MIN_TIME = 500;
@ -57,7 +57,7 @@ export class ChatInput {
public willSendWebPage: any = null;
public replyToMsgID = 0;
public editMsgID = 0;
public noWebPage = false;
public noWebPage: true;
private recorder: any;
private recording = false;
@ -159,7 +159,7 @@ export class ChatInput {
this.setTopInfo(webpage.site_name || webpage.title, webpage.description || webpage.url);
this.replyToMsgID = 0;
this.noWebPage = false;
delete this.noWebPage;
this.willSendWebPage = webpage;
}
});
@ -744,7 +744,7 @@ export class ChatInput {
if(clearInput) {
this.lastUrl = '';
this.editMsgID = 0;
this.noWebPage = false;
delete this.noWebPage;
this.willSendWebPage = null;
this.messageInput.innerText = '';

View File

@ -171,8 +171,8 @@ window.addEventListener('resize', () => {
} */
});
let openedMenu: HTMLDivElement = null, openedMenuOnClose: () => void = null;
export function openBtnMenu(menuElement: HTMLDivElement, onClose?: () => void) {
let openedMenu: HTMLElement = null, openedMenuOnClose: () => void = null;
export function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) {
closeBtnMenu();
openedMenu = menuElement;

View File

@ -1,8 +1,8 @@
import appMessagesManager from "../lib/appManagers/appMessagesManager";
import appPollsManager, { Poll } from "../lib/appManagers/appPollsManager";
import $rootScope from "../lib/rootScope";
import { PopupElement } from "./popup";
import Scrollable from "./scrollable";
import appMessagesManager from "../lib/appManagers/appMessagesManager";
import $rootScope from "../lib/rootScope";
import { Poll } from "../lib/appManagers/appPollsManager";
import { toast } from "./toast";
const InputField = (placeholder: string, label: string, name: string) => {
@ -74,25 +74,21 @@ export default class PopupCreatePoll extends PopupElement {
//const randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)];
//const randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString();
const poll: Partial<Poll> = {};
poll._ = 'poll';
const poll: Poll = {
_: 'poll',
question,
answers: answers.map((value, idx) => {
return {
_: 'pollAnswer',
text: value,
option: new Uint8Array([idx])
};
}),
id: undefined
};
//poll.id = randomIDS;
poll.flags = 0;
poll.question = question;
poll.answers = answers.map((value, idx) => {
return {
_: 'pollAnswer',
text: value,
option: new Uint8Array([idx])
};
});
appMessagesManager.sendOther($rootScope.selectedPeerID, {
_: 'inputMediaPoll',
flags: 0,
poll
});
appMessagesManager.sendOther($rootScope.selectedPeerID, appPollsManager.getInputMediaPoll(poll));
};
onInput = (e: Event) => {

View File

@ -1,12 +1,12 @@
import { SliderTab } from "../../slider";
import appSidebarLeft, { AppSidebarLeft } from "..";
import lottieLoader, { RLottiePlayer } from "../../../lib/lottieLoader";
import appMessagesManager, { MyDialogFilter as DialogFilter } from "../../../lib/appManagers/appMessagesManager";
import { parseMenuButtonsTo } from "../../misc";
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
import appMessagesManager, { MyDialogFilter as DialogFilter } from "../../../lib/appManagers/appMessagesManager";
import lottieLoader, { RLottiePlayer } from "../../../lib/lottieLoader";
import { copy, deepEqual } from "../../../lib/utils";
import { toast } from "../../toast";
import { parseMenuButtonsTo } from "../../misc";
import { ripple } from "../../ripple";
import { SliderTab } from "../../slider";
import { toast } from "../../toast";
const MAX_FOLDER_NAME_LENGTH = 12;
@ -243,7 +243,6 @@ export default class AppEditFolderTab implements SliderTab {
if(filter === undefined) {
this.setFilter({
_: 'dialogFilter',
flags: 0,
id: 0,
title: '',
pFlags: {},

View File

@ -494,14 +494,6 @@
<div id="bubbles-inner"></div>
<div id="bubbles-go-down" class="tgico-down btn-corner z-depth-1 rp hide"></div>
</div>
<div class="btn-menu" id="bubble-contextmenu">
<div class="btn-menu-item menu-reply tgico-reply rp">Reply</div>
<div class="btn-menu-item menu-edit tgico-edit rp">Edit</div>
<div class="btn-menu-item menu-copy tgico-copy rp">Copy</div>
<div class="btn-menu-item menu-pin tgico-pin rp">Pin</div>
<div class="btn-menu-item menu-forward tgico-forward rp">Forward</div>
<div class="btn-menu-item menu-delete tgico-delete danger rp">Delete</div>
</div>
<div id="chat-input" style="display: none;">
<div class="chat-input-container">
<div class="input-message">

View File

@ -1,29 +1,27 @@
import appMessagesManager from "./appMessagesManager";
import apiManagerProxy from "../mtproto/mtprotoworker";
import appPeersManager from "../appManagers/appPeersManager";
import appMessagesIDsManager from "./appMessagesIDsManager";
import { RichTextProcessor } from "../richtextprocessor";
import { toast } from "../../components/toast";
import appUsersManager from "./appUsersManager";
import appPhotosManager from "./appPhotosManager";
import appDocsManager from "./appDocsManager";
import { BotInlineResult } from "../../layer";
import appPeersManager from "../appManagers/appPeersManager";
import apiManagerProxy from "../mtproto/mtprotoworker";
import { RichTextProcessor } from "../richtextprocessor";
import appDocsManager from "./appDocsManager";
import appMessagesIDsManager from "./appMessagesIDsManager";
import appMessagesManager from "./appMessagesManager";
import appPhotosManager from "./appPhotosManager";
import appUsersManager from "./appUsersManager";
export class AppInlineBotsManager {
private inlineResults: {[qID: string]: BotInlineResult} = {};
public getInlineResults(peerID: number, botID: number, query = '', offset = '', geo?: any) {
return apiManagerProxy.invokeApi('messages.getInlineBotResults', {
flags: 0 | (geo ? 1 : 0),
bot: appUsersManager.getUserInput(botID),
peer: appPeersManager.getInputPeerByID(peerID),
query: query,
geo_point: geo && {_: 'inputGeoPoint', lat: geo['lat'], long: geo['long']},
geo_point: (geo && {_: 'inputGeoPoint', lat: geo['lat'], long: geo['long']}) || undefined,
offset
}, {/* timeout: 1, */stopTime: -1, noErrorBox: true}).then(botResults => {
const queryID = botResults.query_id;
/* delete botResults._;
delete botResults.flags;
delete botResults.query_id; */
/* if(botResults.switch_pm) {

View File

@ -1,13 +1,13 @@
//import apiManager from '../mtproto/apiManager';
import { logger, LogLevels } from '../logger';
import apiManager from '../mtproto/mtprotoworker';
import $rootScope from '../rootScope';
//import networkerFactory from '../mtproto/networkerFactory';
import { tsNow } from "../utils";
import appPeersManager from "./appPeersManager";
import appUsersManager from "./appUsersManager";
import appChatsManager from "./appChatsManager";
import { logger, LogLevels } from '../logger';
import $rootScope from '../rootScope';
import appPeersManager from "./appPeersManager";
import appStateManager from './appStateManager';
import appUsersManager from "./appUsersManager";
export class ApiUpdatesManager {
public updatesState: {
@ -160,7 +160,6 @@ export class ApiUpdatesManager {
_: 'updateNewMessage',
message: {
_: 'message',
flags: updateMessage.flags,
pFlags: updateMessage.pFlags,
id: updateMessage.id,
from_id: appPeersManager.getOutputPeer(fromID),
@ -207,7 +206,6 @@ export class ApiUpdatesManager {
}
return apiManager.invokeApi('updates.getDifference', {
flags: 0,
pts: updatesState.pts,
date: updatesState.date,
qts: -1

View File

@ -59,7 +59,7 @@ export type Chat = {
default_banned_rights?: any
};
export type ChatRights = 'send' | 'edit_title' | 'edit_photo' | 'invite' | 'pin' | 'deleteRevoke';
export type ChatRights = 'send' | 'edit_title' | 'edit_photo' | 'invite' | 'pin' | 'deleteRevoke' | 'delete';
export class AppChatsManager {
public chats: {[id: number]: Channel | Chat | any} = {};

View File

@ -1,12 +1,12 @@
import {RichTextProcessor} from '../richtextprocessor';
import { isObject, getFileURL, FileURLType, safeReplaceArrayInObject } from '../utils';
import opusDecodeController from '../opusDecodeController';
import { Document, InputFileLocation, PhotoSize } from '../../layer';
import { getFileNameByLocation } from '../bin_utils';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase';
import opusDecodeController from '../opusDecodeController';
import { RichTextProcessor } from '../richtextprocessor';
import { FileURLType, getFileURL, isObject, safeReplaceArrayInObject } from '../utils';
import appDownloadManager, { DownloadBlob } from './appDownloadManager';
import appPhotosManager from './appPhotosManager';
import { InputFileLocation, Document, PhotoSize } from '../../layer';
import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
export type MyDocument = Document.document;
@ -173,7 +173,6 @@ class AppDocsManager {
public getMediaInput(doc: MyDocument) {
return {
_: 'inputMediaDocument',
flags: 0,
id: {
_: 'inputDocument',
id: doc.id,

View File

@ -1,49 +1,49 @@
//import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker';
import { numberWithCommas, findUpClassName, formatNumber, placeCaretAtEnd, findUpTag, langPack, whichChild, cancelEvent, getObjectKeysAndSort } from "../utils";
import appUsersManager from "./appUsersManager";
import appMessagesManager, { Dialog } from "./appMessagesManager";
import appPeersManager from "./appPeersManager";
import appProfileManager from "./appProfileManager";
import appDialogsManager from "./appDialogsManager";
import { RichTextProcessor } from "../richtextprocessor";
import appPhotosManager from "./appPhotosManager";
import appSidebarRight, { AppSidebarRight, RIGHT_COLUMN_ACTIVE_CLASSNAME } from '../../components/sidebarRight';
import { logger, LogLevels } from "../logger";
import appMediaViewer from "./appMediaViewer";
import appSidebarLeft from "../../components/sidebarLeft";
import appChatsManager, { Channel, Chat } from "./appChatsManager";
import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply, wrapAlbum, wrapPoll } from '../../components/wrappers';
import ProgressivePreloader from '../../components/preloader';
import { formatPhoneNumber, parseMenuButtonsTo } from '../../components/misc';
import { ChatInput } from '../../components/chat/input';
//import Scrollable from '../../components/scrollable';
import Scrollable from '../../components/scrollable';
import BubbleGroups from '../../components/bubbleGroups';
import LazyLoadQueue from '../../components/lazyLoadQueue';
import appDocsManager from './appDocsManager';
import appStickersManager from './appStickersManager';
import AvatarElement from '../../components/avatar';
import appInlineBotsManager from './AppInlineBotsManager';
import StickyIntersector from '../../components/stickyIntersector';
import animationIntersector from '../../components/animationIntersector';
import PopupStickers from '../../components/popupStickers';
import PopupDatePicker from '../../components/popupDatepicker';
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 AvatarElement from '../../components/avatar';
import BubbleGroups from '../../components/bubbleGroups';
import { ChatAudio } from '../../components/chat/audio';
import { ChatContextMenu } from '../../components/chat/contextMenu';
import { ChatInput } from '../../components/chat/input';
import { ChatSearch } from '../../components/chat/search';
import { horizontalMenu } from '../../components/horizontalMenu';
import LazyLoadQueue from '../../components/lazyLoadQueue';
import { formatPhoneNumber, parseMenuButtonsTo } from '../../components/misc';
import PopupDatePicker from '../../components/popupDatepicker';
import PopupStickers from '../../components/popupStickers';
import ProgressivePreloader from '../../components/preloader';
import { ripple } from '../../components/ripple';
//import Scrollable from '../../components/scrollable';
import Scrollable from '../../components/scrollable';
import appSidebarLeft from "../../components/sidebarLeft";
import appSidebarRight, { AppSidebarRight, RIGHT_COLUMN_ACTIVE_CLASSNAME } from '../../components/sidebarRight';
import StickyIntersector from '../../components/stickyIntersector';
import { wrapAlbum, wrapDocument, wrapPhoto, wrapPoll, wrapReply, wrapSticker, wrapVideo } from '../../components/wrappers';
import mediaSizes from '../../helpers/mediaSizes';
import { isAndroid, isApple, isSafari } from '../../helpers/userAgent';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import $rootScope from '../rootScope';
import { isTouchSupported } from '../../helpers/touchSupport';
import { isAndroid, isApple, isSafari } from '../../helpers/userAgent';
import { InputNotifyPeer, InputPeerNotifySettings } from '../../layer';
import { logger, LogLevels } from "../logger";
import apiManager from '../mtproto/mtprotoworker';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from '../rootScope';
import { cancelEvent, findUpClassName, findUpTag, formatNumber, getObjectKeysAndSort, langPack, numberWithCommas, placeCaretAtEnd, whichChild } from "../utils";
import apiUpdatesManager from './apiUpdatesManager';
import appChatsManager, { Channel, Chat } from "./appChatsManager";
import appDialogsManager from "./appDialogsManager";
import appDocsManager from './appDocsManager';
import appInlineBotsManager from './AppInlineBotsManager';
import appMediaViewer from "./appMediaViewer";
import appMessagesManager, { Dialog } from "./appMessagesManager";
import appPeersManager from "./appPeersManager";
import appPhotosManager from "./appPhotosManager";
import appPollsManager from './appPollsManager';
import appProfileManager from "./appProfileManager";
import appStickersManager from './appStickersManager';
import appUsersManager from "./appUsersManager";
//console.log('appImManager included33!');
@ -2612,9 +2612,7 @@ export class AppImManager {
};
let settings: InputPeerNotifySettings = {
_: 'inputPeerNotifySettings',
flags: 0,
mute_until: 0
_: 'inputPeerNotifySettings'
};
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
@ -2624,10 +2622,7 @@ export class AppImManager {
}
if(!muted) {
settings.flags |= 1 << 2;
settings.mute_until = 2147483647;
} else {
settings.flags |= 2;
}
apiManager.invokeApi('account.updateNotifySettings', {
@ -2640,7 +2635,6 @@ export class AppImManager {
/* return apiManager.invokeApi('account.getNotifySettings', {
peer: inputNotifyPeer
}).then((settings: any) => {
settings.flags |= 2 << 1;
settings.mute_until = 2000000000; // 2147483646
return apiManager.invokeApi('account.updateNotifySettings', {

View File

@ -1,33 +1,32 @@
import { copy, tsNow, safeReplaceObject, listMergeSorted, deepEqual, langPack, getObjectKeysAndSort, limitSymbols } from "../utils";
import appMessagesIDsManager from "./appMessagesIDsManager";
import appChatsManager from "./appChatsManager";
import appUsersManager from "./appUsersManager";
import { RichTextProcessor } from "../richtextprocessor";
import { nextRandomInt, bigint } from "../bin_utils";
//import { telegramMeWebService } from "../mtproto/mtproto";
import apiUpdatesManager from "./apiUpdatesManager";
import appPhotosManager, { MyPhoto } from "./appPhotosManager";
import AppStorage from '../storage';
import appPeersManager from "./appPeersManager";
import ServerTimeManager from "../mtproto/serverTimeManager";
import appDocsManager, {MyDocument} from "./appDocsManager";
import ProgressivePreloader from "../../components/preloader";
import serverTimeManager from "../mtproto/serverTimeManager";
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
import { Dialog as MTDialog, DialogFilter, DocumentAttribute, InputMessage, Message, MessagesDialogs, MessagesFilter, MessagesMessages, MessagesPeerDialogs, MethodDeclMap, PhotoSize } from "../../layer";
import { Modify } from "../../types";
import { bigint, nextRandomInt } from "../bin_utils";
import { logger } from "../logger";
import type { ApiFileManager } from '../mtproto/apiFileManager';
//import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker';
import appWebPagesManager from "./appWebPagesManager";
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
import appPollsManager from "./appPollsManager";
import searchIndexManager from '../searchIndexManager';
import { Modify } from "../../types";
import { logger, LogLevels } from "../logger";
import type {ApiFileManager} from '../mtproto/apiFileManager';
import appDownloadManager from "./appDownloadManager";
import { DialogFilter, Message, InputMessage, MethodDeclMap, MessagesFilter, PhotoSize, DocumentAttribute, Dialog as MTDialog, MessagesDialogs, MessagesPeerDialogs, MessagesMessages, MessageMedia } from "../../layer";
import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase";
import { default as ServerTimeManager, default as serverTimeManager } from "../mtproto/serverTimeManager";
import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope";
import searchIndexManager from '../searchIndexManager';
import AppStorage from '../storage';
import { copy, deepEqual, getObjectKeysAndSort, langPack, limitSymbols, listMergeSorted, safeReplaceObject, tsNow } from "../utils";
//import { telegramMeWebService } from "../mtproto/mtproto";
import apiUpdatesManager from "./apiUpdatesManager";
import appChatsManager from "./appChatsManager";
import appDocsManager, { MyDocument } from "./appDocsManager";
import appDownloadManager from "./appDownloadManager";
import appMessagesIDsManager from "./appMessagesIDsManager";
import appPeersManager from "./appPeersManager";
import appPhotosManager, { MyPhoto } from "./appPhotosManager";
import appPollsManager from "./appPollsManager";
import appStateManager from "./appStateManager";
import appUsersManager from "./appUsersManager";
import appWebPagesManager from "./appWebPagesManager";
//console.trace('include');
// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет
@ -345,31 +344,6 @@ export class FiltersStorage {
public updateDialogFilter(filter: MyDialogFilter, remove = false) {
const flags = remove ? 0 : 1;
if(!remove) {
filter.flags = 0;
const f: {[k: string]: number} = {
contacts: 0,
non_contacts: 1,
groups: 2,
broadcasts: 3,
bots: 4,
exclude_muted: 11,
exclude_read: 12,
exclude_archived: 13
};
for(const key in f) {
// @ts-ignore
if(filter.pFlags[key]) {
filter.flags |= 1 << f[key];
}
}
if(filter.emoticon) {
filter.flags |= 1 << 25;
}
}
return apiManager.invokeApi('messages.updateDialogFilter', {
flags,
id: filter.id,
@ -536,10 +510,15 @@ export class AppMessagesManager {
});
$rootScope.$on('webpage_updated', (e) => {
let eventData = e.detail;
const eventData = e.detail;
eventData.msgs.forEach((msgID) => {
let message = this.getMessage(msgID) as Message.message;
(message.media as MessageMedia.messageMediaWebPage).webpage = appWebPagesManager.getWebPage(eventData.id); // warning
const message = this.getMessage(msgID) as Message.message;
if(!message) return;
message.media = {
_: 'messageMediaWebPage',
webpage: appWebPagesManager.getWebPage(eventData.id)
};
$rootScope.$broadcast('message_edit', {
peerID: this.getMessagePeer(message),
id: message.id,
@ -684,11 +663,12 @@ export class AppMessagesManager {
return sendEntites;
}
public editMessage(messageID: number, text: string, options: {
noWebPage?: boolean
} = {}) {
if(typeof(text) !== 'string' || !this.canEditMessage(messageID)) {
return Promise.reject();
public editMessage(messageID: number, text: string, options: Partial<{
noWebPage: true,
newMedia: any
}> = {}) {
if(!this.canEditMessage(messageID)) {
return Promise.reject({type: 'MESSAGE_EDIT_FORBIDDEN'});
}
if(messageID < 0) {
@ -696,7 +676,7 @@ export class AppMessagesManager {
this.tempFinalizeCallbacks[messageID] = {}
}
let promise = new Promise((resolve, reject) => {
const promise = new Promise((resolve, reject) => {
this.tempFinalizeCallbacks[messageID].edit = (mid: number) => {
this.log('invoke callback', mid)
this.editMessage(mid, text).then(resolve, reject);
@ -706,38 +686,27 @@ export class AppMessagesManager {
return promise;
}
var entities: any = [];
text = RichTextProcessor.parseMarkdown(text, entities)
var message = this.getMessage(messageID);
var peerID = this.getMessagePeer(message);
var flags = 0;
let noWebPage = options.noWebPage || false;
if(noWebPage) {
flags |= 2;
let entities: any[];
if(typeof(text) === 'string') {
entities = [];
text = RichTextProcessor.parseMarkdown(text, entities);
}
if(text) {
flags |= 8 | 1 << 11;
}
/* if(message.media) {
flags |= 1 << 14;
} */
const message = this.getMessage(messageID);
const peerID = this.getMessagePeer(message);
return apiManager.invokeApi('messages.editMessage', {
flags: flags,
peer: appPeersManager.getInputPeerByID(peerID),
id: appMessagesIDsManager.getMessageLocalID(messageID),
message: text,
// @ts-ignore
media: message.media,
entities: this.getInputEntities(entities),
no_webpage: noWebPage || undefined,
media: options.newMedia,
entities: entities ? this.getInputEntities(entities) : undefined,
no_webpage: options.noWebPage,
}).then((updates) => {
apiUpdatesManager.processUpdateMessage(updates);
}, (error) => {
this.log.error('editMessage error:', error);
if(error && error.type == 'MESSAGE_NOT_MODIFIED') {
error.handled = true;
return;
@ -755,9 +724,9 @@ export class AppMessagesManager {
viaBotID: number,
queryID: string,
resultID: string,
noWebPage: boolean,
noWebPage: true,
reply_markup: any,
clearDraft: boolean,
clearDraft: true,
webPage: any
}> = {}) {
if(typeof(text) != 'string') {
@ -775,18 +744,20 @@ export class AppMessagesManager {
}
var sendEntites = this.getInputEntities(entities);
if(!sendEntites.length) {
sendEntites = undefined;
}
var messageID = this.tempID--;
var randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)];
var randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString();
var historyStorage = this.historiesStorage[peerID];
var flags = 0;
var pFlags: any = {};
var replyToMsgID = options.replyToMsgID;
var isChannel = appPeersManager.isChannel(peerID);
var isMegagroup = isChannel && appPeersManager.isMegagroup(peerID);
var asChannel = isChannel && !isMegagroup ? true : false;
var message: any;
let noWebPage = options.noWebPage || false;
if(historyStorage === undefined) {
historyStorage = this.historiesStorage[peerID] = {count: null, history: [], pending: []};
@ -794,24 +765,16 @@ export class AppMessagesManager {
var fromID = appUsersManager.getSelf().id;
if(peerID != fromID) {
flags |= 2;
pFlags.out = true;
if(!isChannel && !appUsersManager.isBot(peerID)) {
flags |= 1;
pFlags.unread = true;
}
}
if(replyToMsgID) {
flags |= 8;
}
if(asChannel) {
fromID = 0;
pFlags.post = true;
} else {
flags |= 256;
}
message = {
@ -819,7 +782,6 @@ export class AppMessagesManager {
id: messageID,
from_id: appPeersManager.getOutputPeer(fromID),
peer_id: appPeersManager.getOutputPeer(peerID),
flags: flags,
pFlags: pFlags,
date: tsNow(true) + serverTimeManager.serverTimeOffset,
message: text,
@ -855,53 +817,31 @@ export class AppMessagesManager {
sentRequestOptions.afterMessageID = this.pendingAfterMsgs[peerID].messageID;
}
var flags = 0;
if(replyToMsgID) {
flags |= 1;
}
if(asChannel) {
flags |= 16;
}
if(options.clearDraft) {
flags |= 128;
}
if(noWebPage) {
flags |= 2;
}
var apiPromise: any;
if(options.viaBotID) {
apiPromise = apiManager.invokeApi('messages.sendInlineBotResult', {
flags: flags,
peer: appPeersManager.getInputPeerByID(peerID),
random_id: randomID as any,
reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID),
reply_to_msg_id: replyToMsgID ? appMessagesIDsManager.getMessageLocalID(replyToMsgID) : undefined,
query_id: options.queryID,
id: options.resultID
id: options.resultID,
clear_draft: options.clearDraft
}, sentRequestOptions);
} else {
if(sendEntites.length) {
flags |= 8;
}
apiPromise = apiManager.invokeApi('messages.sendMessage', {
flags: flags,
no_webpage: noWebPage || undefined,
no_webpage: options.noWebPage,
peer: appPeersManager.getInputPeerByID(peerID),
message: text,
random_id: randomID as any,
reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID),
entities: sendEntites
reply_to_msg_id: replyToMsgID ? appMessagesIDsManager.getMessageLocalID(replyToMsgID) : undefined,
entities: sendEntites,
clear_draft: options.clearDraft
}, sentRequestOptions);
}
// this.log(flags, entities)
apiPromise.then((updates: any) => {
if(updates._ == 'updateShortSentMessage') {
message.flags = updates.flags;
message.date = updates.date;
message.id = updates.id;
message.media = updates.media;
@ -1249,7 +1189,6 @@ export class AppMessagesManager {
const inputMedia = {
_: 'inputMediaDocument',
flags: 0,
id: {
_: 'inputDocument',
id: id,
@ -1279,7 +1218,6 @@ export class AppMessagesManager {
case 'photo':
inputMedia = {
_: 'inputMediaUploadedPhoto',
flags: 0,
file: inputFile
};
break;
@ -1561,7 +1499,6 @@ export class AppMessagesManager {
if(details.duration) {
inputMedia = {
_: 'inputMediaUploadedDocument',
flags: 0,
file: inputFile,
mime_type: file.type,
attributes: [{
@ -1576,7 +1513,6 @@ export class AppMessagesManager {
} else {
inputMedia = {
_: 'inputMediaUploadedPhoto',
flags: 0,
file: inputFile
};
}
@ -1600,7 +1536,6 @@ export class AppMessagesManager {
inputs.push({
_: 'inputSingleMedia',
flags: 0,
media: inputMedia,
random_id: message.randomID,
message: caption,
@ -1627,7 +1562,7 @@ export class AppMessagesManager {
replyToMsgID: number,
viaBotID: number,
reply_markup: any,
clearDraft: boolean,
clearDraft: true,
queryID: string
resultID: string
}> = {}) {
@ -1724,24 +1659,17 @@ export class AppMessagesManager {
break; */
}
let flags = 0;
let pFlags: any = {};
if(peerID != fromID) {
flags |= 2;
pFlags.out = true;
if(!appUsersManager.isBot(peerID)) {
flags |= 1;
pFlags.unread = true;
}
}
if(replyToMsgID) {
flags |= 8;
}
if(asChannel) {
fromID = 0;
pFlags.post = true;
} else {
flags |= 256;
}
const message: any = {
@ -1749,7 +1677,6 @@ export class AppMessagesManager {
id: messageID,
from_id: appPeersManager.getOutputPeer(fromID),
peer_id: appPeersManager.getOutputPeer(peerID),
flags: flags,
pFlags: pFlags,
date: tsNow(true) + ServerTimeManager.serverTimeOffset,
message: '',
@ -1779,17 +1706,6 @@ export class AppMessagesManager {
};
message.send = () => {
let flags = 0;
if(replyToMsgID) {
flags |= 1;
}
if(asChannel) {
flags |= 16;
}
if(options.clearDraft) {
flags |= 128;
}
const sentRequestOptions: any = {};
if(this.pendingAfterMsgs[peerID]) {
sentRequestOptions.afterMessageID = this.pendingAfterMsgs[peerID].messageID;
@ -1798,23 +1714,24 @@ export class AppMessagesManager {
let apiPromise: Promise<any>;
if(options.viaBotID) {
apiPromise = apiManager.invokeApi('messages.sendInlineBotResult', {
flags: flags,
peer: appPeersManager.getInputPeerByID(peerID),
random_id: randomID as any,
reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID),
reply_to_msg_id: replyToMsgID ? appMessagesIDsManager.getMessageLocalID(replyToMsgID) : undefined,
query_id: options.queryID,
id: options.resultID
id: options.resultID,
clear_draft: options.clearDraft
}, sentRequestOptions);
} else {
apiPromise = apiManager.invokeApi('messages.sendMedia', {
flags: flags,
peer: appPeersManager.getInputPeerByID(peerID),
media: inputMedia,
random_id: randomID as any,
reply_to_msg_id: appMessagesIDsManager.getMessageLocalID(replyToMsgID),
message: ''
reply_to_msg_id: replyToMsgID ? appMessagesIDsManager.getMessageLocalID(replyToMsgID) : undefined,
message: '',
clear_draft: options.clearDraft
}, sentRequestOptions);
}
apiPromise.then((updates) => {
if(updates.updates) {
updates.updates.forEach((update: any) => {
@ -1849,15 +1766,15 @@ export class AppMessagesManager {
}
public cancelPendingMessage(randomID: string) {
var pendingData = this.pendingByRandomID[randomID];
const pendingData = this.pendingByRandomID[randomID];
this.log('cancelPendingMessage', randomID, pendingData);
if(pendingData) {
var peerID = pendingData[0];
var tempID = pendingData[1];
var historyStorage = this.historiesStorage[peerID];
var pos = historyStorage.pending.indexOf(tempID);
const peerID = pendingData[0];
const tempID = pendingData[1];
const historyStorage = this.historiesStorage[peerID];
const pos = historyStorage.pending.indexOf(tempID);
apiUpdatesManager.processUpdateMessage({
_: 'updateShort',
@ -2140,12 +2057,6 @@ export class AppMessagesManager {
var toID = message.peer_id && appPeersManager.getPeerID(message.peer_id) || 0;
return toID;
/* if(toID < 0) {
return toID;
} else if(message.pFlags && message.pFlags.out || message.flags & 2) {
return toID;
}
return message.from_id; */
}
public getDialogByPeerID(peerID: number): [Dialog, number] | [] {
@ -2264,7 +2175,6 @@ export class AppMessagesManager {
public updatePinnedMessage(peerID: number, msgID: number) {
apiManager.invokeApi('messages.updatePinnedMessage', {
flags: 0,
peer: appPeersManager.getInputPeerByID(peerID),
id: msgID
}).then(updates => {
@ -2679,12 +2589,14 @@ export class AppMessagesManager {
}
public canMessageBeEdited(message: any) {
var goodMedias = [
const goodMedias = [
'messageMediaPhoto',
'messageMediaDocument',
'messageMediaWebPage',
'messageMediaPending'
]
'messageMediaPending',
'messageMediaPoll'
];
if(message._ != 'message' ||
message.deleted ||
message.fwd_from ||
@ -2693,6 +2605,7 @@ export class AppMessagesManager {
message.fromID && appUsersManager.isBot(message.fromID)) {
return false;
}
if(message.media &&
message.media._ == 'messageMediaDocument' &&
message.media.document.sticker) {
@ -2716,7 +2629,7 @@ export class AppMessagesManager {
return true;
}
if(message.date < tsNow(true) - 2 * 86400 || !message.pFlags.out) {
if((message.date < tsNow(true) - (2 * 86400) && message.media?._ != 'messageMediaPoll') || !message.pFlags.out) {
return false;
}
@ -2817,7 +2730,6 @@ export class AppMessagesManager {
from_id: appPeersManager.getOutputPeer(appUsersManager.getSelf().id),
peer_id: appPeersManager.getOutputPeer(peerID),
deleted: true,
flags: 0,
pFlags: {out: true},
date: 0,
message: ''
@ -2903,8 +2815,7 @@ export class AppMessagesManager {
return false;
}
if(messageReplyMarkup.pFlags.selective &&
!(message.flags & 16)) {
if(messageReplyMarkup.pFlags.selective) {
return false;
}
@ -2950,7 +2861,6 @@ export class AppMessagesManager {
historyStorage.reply_markup = {
_: 'replyKeyboardHide',
mid: message.mid,
flags: 0,
pFlags: {}
};
// this.log('set', historyStorage.reply_markup)
@ -3108,7 +3018,6 @@ export class AppMessagesManager {
let apiPromise: Promise<any>;
if(peerID || !query) {
apiPromise = apiManager.invokeApi('messages.search', {
flags: 0,
peer: appPeersManager.getInputPeerByID(peerID),
q: query || '',
filter: (inputFilter || {_: 'inputMessagesFilterEmpty'}) as any as MessagesFilter,
@ -3137,7 +3046,6 @@ export class AppMessagesManager {
}
apiPromise = apiManager.invokeApi('messages.searchGlobal', {
flags: 0,
q: query,
filter: (inputFilter || {_: 'inputMessagesFilterEmpty'}) as any as MessagesFilter,
min_date: 0,
@ -3893,7 +3801,6 @@ export class AppMessagesManager {
id: messageID,
from_id: message.from_id,
peer_id: message.peer_id,
flags: message.flags,
pFlags: message.pFlags,
date: message.date
};
@ -4026,7 +3933,6 @@ export class AppMessagesManager {
id: messageID,
from_id: appPeersManager.getOutputPeer(fromID),
peer_id: appPeersManager.getOutputPeer(peerID),
flags: 0,
pFlags: {unread: true},
date: (update.inbox_date || tsNow(true)) + serverTimeManager.serverTimeOffset,
message: update.message,
@ -4387,7 +4293,6 @@ export class AppMessagesManager {
id: messageID,
from_id: peerID,
peer_id: appPeersManager.getOutputPeer(peerID),
flags: 0,
pFlags: {},
date: tsNow(true) + serverTimeManager.serverTimeOffset,
action: {

View File

@ -1,11 +1,11 @@
import { calcImageInBox, isObject, safeReplaceArrayInObject } from "../utils";
import { bytesFromHex, getFileNameByLocation } from "../bin_utils";
import appDownloadManager from "./appDownloadManager";
import { CancellablePromise } from "../../helpers/cancellablePromise";
import { isSafari } from "../../helpers/userAgent";
import { FileLocation, InputFileLocation, Photo, PhotoSize } from "../../layer";
import { MyDocument } from "./appDocsManager";
import { CancellablePromise } from "../../helpers/cancellablePromise";
import { bytesFromHex, getFileNameByLocation } from "../bin_utils";
import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase";
import { calcImageInBox, isObject, safeReplaceArrayInObject } from "../utils";
import { MyDocument } from "./appDocsManager";
import appDownloadManager from "./appDownloadManager";
export type MyPhoto = Photo.photo;
@ -303,7 +303,6 @@ export class AppPhotosManager {
public getInput(photo: MyPhoto) {
return {
_: 'inputMediaPhoto',
flags: 0,
id: {
_: 'inputPhoto',
id: photo.id,

View File

@ -1,12 +1,13 @@
import { logger, LogLevels } from "../logger";
import apiManager from "../mtproto/mtprotoworker";
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope";
import { copy } from "../utils";
import apiUpdatesManager from "./apiUpdatesManager";
import appMessagesManager from './appMessagesManager';
import appPeersManager from './appPeersManager';
import apiManager from "../mtproto/mtprotoworker";
import apiUpdatesManager from "./apiUpdatesManager";
import $rootScope from "../rootScope";
import { logger, LogLevels } from "../logger";
import appUsersManager from "./appUsersManager";
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
export type PollAnswer = {
_: 'pollAnswer',
@ -51,7 +52,6 @@ export type PollResults = {
export type Poll = {
_: 'poll',
flags: number,
question: string,
id: string,
answers: Array<PollAnswer>,
@ -140,6 +140,13 @@ class AppPollsManager {
};
}
public getInputMediaPoll(poll: Poll) {
return {
_: 'inputMediaPoll',
poll
};
}
public sendVote(mid: number, optionIDs: number[]) {
const message = appMessagesManager.getMessage(mid);
const poll: Poll = message.media.poll;
@ -204,6 +211,23 @@ class AppPollsManager {
return votesList;
});
}
public stopPoll(mid: number) {
const message = appMessagesManager.getMessage(mid);
const poll: Poll = message.media.poll;
if(poll.pFlags.closed) return Promise.resolve();
const newPoll = copy(poll);
newPoll.pFlags.closed = true;
return appMessagesManager.editMessage(mid, undefined, {
newMedia: this.getInputMediaPoll(newPoll)
}).then(() => {
//console.log('stopped poll');
}, err => {
this.log.error('stopPoll error:', err);
});
}
}
const appPollsManager = new AppPollsManager();

View File

@ -1,10 +1,10 @@
import apiManager from '../mtproto/mtprotoworker';
import appDocsManager from './appDocsManager';
import $rootScope from '../rootScope';
import { StickerSet, InputStickerSet, StickerSetCovered, MessagesRecentStickers, Document, InputFileLocation, MessagesStickerSet, PhotoSize } from '../../layer';
import { Document, InputFileLocation, InputStickerSet, MessagesRecentStickers, MessagesStickerSet, PhotoSize, StickerSet, StickerSetCovered } from '../../layer';
import { Modify } from '../../types';
import appStateManager from './appStateManager';
import apiManager from '../mtproto/mtprotoworker';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import $rootScope from '../rootScope';
import appDocsManager from './appDocsManager';
import appStateManager from './appStateManager';
// TODO: если пак будет сохранён и потом обновлён, то недостающие стикеры не подгрузит
@ -86,7 +86,7 @@ export class AppStickersManager {
public async getRecentStickers(): Promise<Modify<MessagesRecentStickers.messagesRecentStickers, {
stickers: Document[]
}>> {
const res = await apiManager.invokeApi('messages.getRecentStickers', {flags: 0, hash: 0}) as MessagesRecentStickers.messagesRecentStickers;
const res = await apiManager.invokeApi('messages.getRecentStickers') as MessagesRecentStickers.messagesRecentStickers;
if(res._ == 'messages.recentStickers') {
this.saveStickers(res.stickers);

View File

@ -1,5 +1,5 @@
import apiManager from './mtprotoworker';
import { AccountPassword } from '../../layer';
import apiManager from './mtprotoworker';
import { MOUNT_CLASS_TO } from './mtproto_config';
//import { computeCheck } from "../crypto/srp";
@ -16,7 +16,6 @@ export class PasswordManager {
var params: any = {
new_settings: {
_: 'account.passwordInputSettings',
flags: 0,
hint: settings.hint || ''
}
};
@ -35,17 +34,14 @@ export class PasswordManager {
secureRandom.nextBytes(saltRandom);
newHashPromise = this.makePasswordHash(newSalt, settings.new_password);
params.new_settings.new_salt = newSalt;
params.new_settings.flags |= 1;
} else {
if(typeof settings.new_password === 'string') {
params.new_settings.flags |= 1;
params.new_settings.new_salt = [];
}
newHashPromise = Promise.resolve([]);
}
if(typeof settings.email === 'string') {
params.new_settings.flags |= 2;
params.new_settings.email = settings.email || '';
}

File diff suppressed because one or more lines are too long

View File

@ -1,12 +1,9 @@
import {bigint, bigStringInt, bytesCmp, bytesToHex, isObject} from '../bin_utils';
import Schema from './schema';
import { bigint, bigStringInt, bytesToHex, isObject } from '../bin_utils';
/// #if MTPROTO_WORKER
// @ts-ignore
import {gzipUncompress} from '../crypto/crypto_utils';
/// #else
// @ts-ignore
import {gzipUncompress} from '../bin_utils';
import { gzipUncompress } from '../crypto/crypto_utils';
import Schema, { MTProtoConstructor } from './schema';
/// #endif
const boolFalse = +Schema.API.constructors.find(c => c.predicate == 'boolFalse').id >>> 0;
@ -91,13 +88,16 @@ class TLSerialization {
public writeInt(i: number, field: string) {
this.debug && console.log('>>>', i.toString(16), i, field);
const offset = this.offset / 4;
this.checkLength(4);
this.intView[this.offset / 4] = i;
this.intView[offset] = i;
this.offset += 4;
return offset;
}
public storeInt(i: number, field?: string) {
this.writeInt(i, (field || '') + ':int');
return this.writeInt(i, (field || '') + ':int');
}
public storeBool(i: boolean, field?: string) {
@ -234,42 +234,51 @@ class TLSerialization {
}
public storeMethod(methodName: string, params: any) {
var schema = this.mtproto ? Schema.MTProto : Schema.API;
var methodData: any = false,
i;
for(i = 0; i < schema.methods.length; i++) {
if(schema.methods[i].method == methodName) {
methodData = schema.methods[i];
break;
}
}
const schema = this.mtproto ? Schema.MTProto : Schema.API;
const methodData = schema.methods.find(m => m.method == methodName);
if(!methodData) {
throw new Error('No method ' + methodName + ' found');
}
this.storeInt(methodData.id, methodName + '[id]');
var param, type;
var i, condType;
var fieldBit;
var len = methodData.params.length;
const pFlags = params.pFlags;
const flagsOffsets: {[paramName: string]: number} = {};
//console.log('storeMethod', len, methodData);
for(i = 0; i < len; i++) {
param = methodData.params[i];
type = param.type;
for(const param of methodData.params) {
let type = param.type;
if(type.indexOf('?') !== -1) {
condType = type.split('?');
fieldBit = condType[0].split('.');
if(!(params[fieldBit[0]] & (1 << fieldBit[1]))) {
continue;
const condType = type.split('?');
const fieldBit = condType[0].split('.');
if(!(params[fieldBit[0]] & (1 << +fieldBit[1]))) {
if((condType[1] === 'true' && pFlags && pFlags[param.name]) || params[param.name] !== undefined) {
//console.log('storeMethod autocompleting', methodName, param.name, params[param.name], type);
params[fieldBit[0]] |= 1 << +fieldBit[1];
} else {
continue;
}
}
//console.log('storeMethod', methodName, fieldBit, params[fieldBit[0]], params, param, condType, !!(params[fieldBit[0]] & (1 << +fieldBit[1])));
type = condType[1];
}
this.storeObject(params[param.name], type, methodName + '[' + param.name + ']');
//console.log('storeMethod', methodName, param.name, params[param.name], type);
const result = this.storeObject(params[param.name], type, methodName + '[' + param.name + ']');
if(type == '#') {
params[param.name] = params[param.name] || 0;
flagsOffsets[param.name] = result as number;
}
}
for(let paramName in flagsOffsets) {
this.intView[flagsOffsets[paramName]] = params[paramName];
}
return methodData.type;
}
@ -277,6 +286,7 @@ class TLSerialization {
//console.log('storeObject', obj, type, field, this.offset, this.getBytes(true).hex);
switch(type) {
case '#':
obj = obj || 0;
case 'int':
return this.storeInt(obj, field);
case 'long':
@ -321,21 +331,15 @@ class TLSerialization {
throw new Error('Invalid object for type ' + type);
}
var schema = this.mtproto ? Schema.MTProto : Schema.API;
var predicate = obj['_'];
var isBare = false;
var constructorData: any = false;
const schema = this.mtproto ? Schema.MTProto : Schema.API;
const predicate = obj['_'];
let isBare = false;
const constructorData: MTProtoConstructor = schema.constructors.find(c => c.predicate == predicate);
if(isBare = (type.charAt(0) == '%')) {
type = type.substr(1);
}
for(i = 0; i < schema.constructors.length; i++) {
if(schema.constructors[i].predicate == predicate) {
constructorData = schema.constructors[i];
break;
}
}
if(!constructorData) {
throw new Error('No predicate ' + predicate + ' found');
}
@ -347,29 +351,43 @@ class TLSerialization {
if(!isBare) {
this.writeInt(constructorData.id, field + '[' + predicate + '][id]');
}
var param, type: string;
var condType;
var fieldBit;
var len = constructorData.params.length;
const pFlags = obj.pFlags;
const flagsOffsets: {[paramName: string]: number} = {};
//console.log('storeObject', len, constructorData);
for(i = 0; i < len; i++) {
param = constructorData.params[i];
type = param.type;
for(const param of constructorData.params) {
let type = param.type;
//console.log('storeObject', param, type);
if(type.indexOf('?') !== -1) {
condType = type.split('?');
fieldBit = condType[0].split('.');
const condType = type.split('?');
const fieldBit = condType[0].split('.');
//console.log('storeObject fieldBit', fieldBit, obj[fieldBit[0]]);
if(!(obj[fieldBit[0]] & (1 << +fieldBit[1]))) {
continue;
if((condType[1] === 'true' && pFlags && pFlags[param.name]) || obj[param.name] !== undefined) {
//console.log('storeObject autocompleting', param.name, obj[param.name], type);
obj[fieldBit[0]] |= 1 << +fieldBit[1];
} else {
continue;
}
}
type = condType[1];
}
//console.log('storeObject', param, type);
this.storeObject(obj[param.name], type, field + '[' + predicate + '][' + param.name + ']');
const result = this.storeObject(obj[param.name], type, field + '[' + predicate + '][' + param.name + ']');
if(type == '#') {
obj[param.name] = obj[param.name] || 0;
flagsOffsets[param.name] = result as number;
}
}
for(let paramName in flagsOffsets) {
this.intView[flagsOffsets[paramName]] = obj[paramName];
}
return constructorData.type;
@ -767,4 +785,5 @@ class TLDeserialization {
}
}
export {TLDeserialization, TLSerialization};
export { TLDeserialization, TLSerialization };

View File

@ -359,15 +359,15 @@ export function whichChild(elem: Node) {
return i;
};
export function copy(obj: any) {
export function copy<T>(obj: T): T {
//in case of premitives
if(obj===null || typeof obj !== "object"){
if(obj === null || typeof(obj) !== "object") {
return obj;
}
//date objects should be
if(obj instanceof Date){
return new Date(obj.getTime());
if(obj instanceof Date) {
return new Date(obj.getTime()) as any;
}
//handle Array
@ -380,6 +380,7 @@ export function copy(obj: any) {
}
//lastly, handle objects
// @ts-ignore
let clonedObj = new obj.constructor();
for(var prop in obj){
if(obj.hasOwnProperty(prop)){

View File

@ -1,14 +1,14 @@
import pageSignIn from './pageSignIn';
import pageSignUp from './pageSignUp';
import pageIm from './pageIm';
import pagePassword from './pagePassword';
import mediaSizes from '../helpers/mediaSizes';
import LottieLoader, { RLottiePlayer } from '../lib/lottieLoader';
//import CryptoWorker from '../lib/crypto/cryptoworker';
//import apiManager from '../lib/mtproto/apiManager';
import apiManager from '../lib/mtproto/mtprotoworker';
import Page from './page';
import { App } from '../lib/mtproto/mtproto_config';
import mediaSizes from '../helpers/mediaSizes';
import Page from './page';
import pageIm from './pageIm';
import pagePassword from './pagePassword';
import pageSignIn from './pageSignIn';
import pageSignUp from './pageSignUp';
let authCode: {
_: string, // 'auth.sentCode'
@ -53,13 +53,11 @@ let onFirstMount = (): Promise<any> => {
codeInput.setAttribute('disabled', 'true');
changePhonePromise = apiManager.invokeApi('auth.sendCode', {
/* flags: 0, */
phone_number: phone_number,
api_id: App.id,
api_hash: App.hash,
settings: {
_: 'codeSettings', // that's how we sending Type
flags: 0
_: 'codeSettings' // that's how we sending Type
}
/* lang_code: navigator.language || 'en' */
}).then((code: any) => {

View File

@ -1,14 +1,14 @@
import { putPreloader, formatPhoneNumber } from "../components/misc";
import { formatPhoneNumber, putPreloader } from "../components/misc";
import Scrollable from '../components/scrollable';
import {RichTextProcessor} from '../lib/richtextprocessor';
import Config from '../lib/config';
import apiManager from "../lib/mtproto/mtprotoworker";
import { App, Modes } from "../lib/mtproto/mtproto_config";
import { RichTextProcessor } from '../lib/richtextprocessor';
import { findUpTag } from "../lib/utils";
import Page from "./page";
import pageAuthCode from "./pageAuthCode";
import pageSignQR from './pageSignQR';
import apiManager from "../lib/mtproto/mtprotoworker";
import Page from "./page";
import { App, Modes } from "../lib/mtproto/mtproto_config";
type Country = {
name: string,
@ -237,13 +237,11 @@ let onFirstMount = () => {
let phone_number = telEl.value;
apiManager.invokeApi('auth.sendCode', {
//flags: 0,
phone_number: phone_number,
api_id: App.id,
api_hash: App.hash,
settings: {
_: 'codeSettings', // that's how we sending Type
flags: 0
_: 'codeSettings' // that's how we sending Type
}
//lang_code: navigator.language || 'en'
}).then((code: any) => {