Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
8.2 KiB
278 lines
8.2 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
* |
|
* Originally from: |
|
* https://github.com/zhukov/webogram |
|
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com> |
|
* https://github.com/zhukov/webogram/blob/master/LICENSE |
|
*/ |
|
|
|
import rootScope from "../rootScope"; |
|
import appPeersManager from "./appPeersManager"; |
|
import appMessagesManager from "./appMessagesManager"; |
|
import apiUpdatesManager from "./apiUpdatesManager"; |
|
import RichTextProcessor from "../richtextprocessor"; |
|
import serverTimeManager from "../mtproto/serverTimeManager"; |
|
import { MessageEntity, DraftMessage, MessagesSaveDraft } from "../../layer"; |
|
import apiManager from "../mtproto/mtprotoworker"; |
|
import { tsNow } from "../../helpers/date"; |
|
import { deepEqual } from "../../helpers/object"; |
|
import { isObject } from "../mtproto/bin_utils"; |
|
import { MOUNT_CLASS_TO } from "../../config/debug"; |
|
import stateStorage from "../stateStorage"; |
|
import appMessagesIdsManager from "./appMessagesIdsManager"; |
|
|
|
export type MyDraftMessage = DraftMessage.draftMessage; |
|
|
|
export class AppDraftsManager { |
|
private drafts: {[peerIdAndThreadId: string]: MyDraftMessage} = {}; |
|
private getAllDraftPromise: Promise<void> = null; |
|
|
|
constructor() { |
|
stateStorage.get('drafts').then(drafts => { |
|
this.drafts = drafts || {}; |
|
}); |
|
|
|
rootScope.addMultipleEventsListeners({ |
|
updateDraftMessage: (update) => { |
|
const peerID = appPeersManager.getPeerId(update.peer); |
|
this.saveDraft(peerID, update.threadId, update.draft, {notify: true}); |
|
} |
|
}); |
|
} |
|
|
|
private getKey(peerId: number, threadId?: number) { |
|
return '' + peerId + (threadId ? '_' + threadId : ''); |
|
} |
|
|
|
public getDraft(peerId: number, threadId?: number) { |
|
return this.drafts[this.getKey(peerId, threadId)]; |
|
} |
|
|
|
public addMissedDialogs() { |
|
return this.getAllDrafts().then(() => { |
|
for(const key in this.drafts) { |
|
if(key.indexOf('_') !== -1) { // exclude threads |
|
continue; |
|
} |
|
|
|
const peerId = +key; |
|
const dialog = appMessagesManager.getDialogOnly(peerId); |
|
if(!dialog) { |
|
appMessagesManager.reloadConversation(peerId); |
|
/* const dialog = appMessagesManager.generateDialog(peerId); |
|
dialog.draft = this.drafts[key]; |
|
appMessagesManager.saveConversation(dialog); |
|
appMessagesManager.newDialogsToHandle[peerId] = dialog; |
|
appMessagesManager.scheduleHandleNewDialogs(); */ |
|
} |
|
} |
|
}); |
|
} |
|
|
|
public getAllDrafts() { |
|
return this.getAllDraftPromise || ( |
|
this.getAllDraftPromise = apiManager.invokeApi('messages.getAllDrafts') |
|
.then((updates) => { |
|
const p = apiUpdatesManager.updatesState.syncLoading || Promise.resolve(); |
|
p.then(() => { |
|
apiUpdatesManager.processUpdateMessage(updates); |
|
}); |
|
}) |
|
); |
|
} |
|
|
|
public saveDraft(peerId: number, threadId: number, apiDraft: DraftMessage, options: Partial<{ |
|
notify: boolean, |
|
force: boolean |
|
}> = {}) { |
|
const draft = this.processApiDraft(apiDraft); |
|
|
|
const key = this.getKey(peerId, threadId); |
|
if(draft) { |
|
this.drafts[key] = draft; |
|
} else { |
|
delete this.drafts[key]; |
|
} |
|
|
|
stateStorage.set({ |
|
drafts: this.drafts |
|
}); |
|
|
|
if(options.notify) { |
|
// console.warn(dT(), 'save draft', peerId, apiDraft, options) |
|
rootScope.dispatchEvent('draft_updated', { |
|
peerId, |
|
threadId, |
|
draft, |
|
force: options.force |
|
}); |
|
} |
|
|
|
return draft; |
|
} |
|
|
|
public draftsAreEqual(draft1: DraftMessage, draft2: DraftMessage) { |
|
if(typeof(draft1) !== typeof(draft2)) { |
|
return false; |
|
} |
|
|
|
if(!isObject(draft1)) { |
|
return true; |
|
} |
|
|
|
if(draft1._ !== draft2._) { |
|
return false; |
|
} |
|
|
|
if(draft1._ === 'draftMessage' && draft2._ === draft1._) { |
|
if(draft1.reply_to_msg_id !== draft2.reply_to_msg_id) { |
|
return false; |
|
} |
|
|
|
if(!deepEqual(draft1.entities, draft2.entities)) { |
|
return false; |
|
} |
|
|
|
if(draft1.message !== draft2.message) { |
|
return false; |
|
} |
|
|
|
if(draft1.pFlags.no_webpage !== draft2.pFlags.no_webpage) { |
|
return false; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
public isEmptyDraft(draft: DraftMessage) { |
|
if(!draft || draft._ === 'draftMessageEmpty') { |
|
return true; |
|
} |
|
|
|
if(draft.reply_to_msg_id > 0) { |
|
return false; |
|
} |
|
|
|
if(!draft.message.length) { |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
public processApiDraft(draft: DraftMessage): MyDraftMessage { |
|
if(!draft || draft._ !== 'draftMessage') { |
|
return undefined; |
|
} |
|
|
|
const myEntities = RichTextProcessor.parseEntities(draft.message); |
|
const apiEntities = draft.entities || []; |
|
const totalEntities = RichTextProcessor.mergeEntities(apiEntities.slice(), myEntities); // ! only in this order, otherwise bold and emoji formatting won't work |
|
|
|
draft.rMessage = RichTextProcessor.wrapDraftText(draft.message, {entities: totalEntities}); |
|
//draft.rReply = appMessagesManager.getRichReplyText(draft); |
|
if(draft.reply_to_msg_id) { |
|
draft.reply_to_msg_id = appMessagesIdsManager.generateMessageId(draft.reply_to_msg_id); |
|
} |
|
|
|
return draft; |
|
} |
|
|
|
public async syncDraft(peerId: number, threadId: number, localDraft?: MyDraftMessage, saveOnServer = true, force = false) { |
|
// console.warn(dT(), 'sync draft', peerID) |
|
const serverDraft = this.getDraft(peerId, threadId); |
|
if(this.draftsAreEqual(serverDraft, localDraft)) { |
|
// console.warn(dT(), 'equal drafts', localDraft, serverDraft) |
|
return true; |
|
} |
|
|
|
// console.warn(dT(), 'changed draft', localDraft, serverDraft) |
|
let params: MessagesSaveDraft = { |
|
peer: appPeersManager.getInputPeerById(peerId), |
|
message: '' |
|
}; |
|
|
|
let draftObj: DraftMessage; |
|
if(this.isEmptyDraft(localDraft)) { |
|
draftObj = {_: 'draftMessageEmpty'}; |
|
} else { |
|
let message = localDraft.message; |
|
let entities: MessageEntity[] = localDraft.entities; |
|
|
|
if(localDraft.reply_to_msg_id) { |
|
params.reply_to_msg_id = appMessagesIdsManager.getServerMessageId(localDraft.reply_to_msg_id); |
|
} |
|
|
|
if(entities?.length) { |
|
params.entities = appMessagesManager.getInputEntities(entities); |
|
} |
|
|
|
if(localDraft.pFlags.no_webpage) { |
|
params.no_webpage = localDraft.pFlags.no_webpage; |
|
} |
|
|
|
params.message = message; |
|
} |
|
|
|
const saveLocalDraft = draftObj || localDraft; |
|
saveLocalDraft.date = tsNow(true) + serverTimeManager.serverTimeOffset; |
|
|
|
this.saveDraft(peerId, threadId, saveLocalDraft, {notify: true, force}); |
|
|
|
if(saveOnServer && !threadId) { |
|
return apiManager.invokeApi('messages.saveDraft', params); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
public clearAllDrafts() { |
|
return apiManager.invokeApi('messages.clearAllDrafts').then(bool => { |
|
if(!bool) { |
|
return; |
|
} |
|
|
|
for(const peerId in this.drafts) { |
|
const splitted = peerId.split('_'); |
|
const threadId = splitted[1]; |
|
rootScope.dispatchEvent('draft_updated', { |
|
peerId: +splitted[0], |
|
threadId: threadId ? +threadId : undefined, |
|
draft: undefined |
|
}); |
|
} |
|
}); |
|
} |
|
|
|
public clearDraft(peerId: number, threadId: number) { |
|
if(threadId) { |
|
this.syncDraft(peerId, threadId); |
|
} else { |
|
this.saveDraft(peerId, threadId, null, {notify: true/* , force: true */}); |
|
} |
|
} |
|
|
|
public setDraft(peerId: number, threadId: number, message: string, entities?: MessageEntity[]) { |
|
const draft: DraftMessage.draftMessage = { |
|
_: 'draftMessage', |
|
date: Date.now() / 1000 | 0, |
|
message, |
|
pFlags: {}, |
|
entities |
|
}; |
|
|
|
if(threadId) { |
|
this.syncDraft(peerId, threadId, draft, false, true); |
|
} else { |
|
this.saveDraft(peerId, threadId, draft, {notify: true, force: true}); |
|
} |
|
} |
|
} |
|
|
|
const appDraftsManager = new AppDraftsManager(); |
|
MOUNT_CLASS_TO.appDraftsManager = appDraftsManager; |
|
export default appDraftsManager;
|
|
|