Comments alpha version
This commit is contained in:
parent
16ed79a74d
commit
7e464418a6
|
@ -66,7 +66,7 @@ function wrapVoiceMessage(audioEl: AudioElement) {
|
|||
audioEl.classList.add('is-voice');
|
||||
|
||||
const message = audioEl.message;
|
||||
const doc = message.media.document as MyDocument;
|
||||
const doc = (message.media.document || message.media.webpage.document) as MyDocument;
|
||||
const isOut = message.fromId == rootScope.myId && message.peerId != rootScope.myId;
|
||||
let isUnread = message && message.pFlags.media_unread;
|
||||
if(isUnread) {
|
||||
|
@ -254,7 +254,7 @@ function wrapVoiceMessage(audioEl: AudioElement) {
|
|||
function wrapAudio(audioEl: AudioElement) {
|
||||
const withTime = audioEl.withTime;
|
||||
|
||||
const doc = audioEl.message.media.document;
|
||||
const doc = audioEl.message.media.document || audioEl.message.media.webpage.document;
|
||||
const title = doc.audioTitle || doc.file_name;
|
||||
let subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : '';
|
||||
|
||||
|
@ -334,7 +334,7 @@ export default class AudioElement extends HTMLElement {
|
|||
|
||||
this.classList.add('audio');
|
||||
|
||||
const doc = this.message.media.document;
|
||||
const doc = this.message.media.document || this.message.media.webpage.document;
|
||||
const uploading = this.message.pFlags.is_outgoing;
|
||||
|
||||
const durationStr = String(doc.duration | 0).toHHMMSS(true);
|
||||
|
@ -360,7 +360,7 @@ export default class AudioElement extends HTMLElement {
|
|||
audioTimeDiv.innerHTML = durationStr;
|
||||
|
||||
const onLoad = (autoload = true) => {
|
||||
const audio = this.audio = appMediaPlaybackController.addMedia(this.message.peerId, this.message.media.document, this.message.mid, autoload);
|
||||
const audio = this.audio = appMediaPlaybackController.addMedia(this.message.peerId, this.message.media.document || this.message.media.webpage.document, this.message.mid, autoload);
|
||||
|
||||
this.onTypeDisconnect = onTypeLoad();
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import Chat from "./chat";
|
|||
import ListenerSetter from "../../helpers/listenerSetter";
|
||||
import PollElement from "../poll";
|
||||
import AudioElement from "../audio";
|
||||
import { MessageReplies, MessageReplyHeader } from "../../layer";
|
||||
|
||||
const IGNORE_ACTIONS = ['messageActionHistoryClear'];
|
||||
|
||||
|
@ -104,7 +105,7 @@ export default class ChatBubbles {
|
|||
public replyFollowHistory: number[] = [];
|
||||
|
||||
constructor(private chat: Chat, private appMessagesManager: AppMessagesManager, private appStickersManager: AppStickersManager, private appUsersManager: AppUsersManager, private appInlineBotsManager: AppInlineBotsManager, private appPhotosManager: AppPhotosManager, private appDocsManager: AppDocsManager, private appPeersManager: AppPeersManager, private appChatsManager: AppChatsManager) {
|
||||
this.chat.log.error('Bubbles construction');
|
||||
//this.chat.log.error('Bubbles construction');
|
||||
|
||||
this.listenerSetter = new ListenerSetter();
|
||||
|
||||
|
@ -358,10 +359,9 @@ export default class ChatBubbles {
|
|||
this.listenerSetter.add(rootScope, 'dialog_unread', (e) => {
|
||||
const info = e.detail;
|
||||
|
||||
const dialog = this.appMessagesManager.getDialogByPeerId(info.peerId)[0];
|
||||
if(dialog?.peerId == this.peerId) {
|
||||
if(info.peerId == this.peerId) {
|
||||
this.chat.input.setUnreadCount();
|
||||
this.updateUnreadByDialog(dialog);
|
||||
this.updateUnreadByDialog();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -510,6 +510,21 @@ export default class ChatBubbles {
|
|||
return;
|
||||
}
|
||||
|
||||
const commentsDiv: HTMLElement = findUpClassName(target, 'replies-footer');
|
||||
if(commentsDiv) {
|
||||
const mid = +bubble.dataset.mid;
|
||||
const message = this.chat.getMessage(mid);
|
||||
const replies = message.replies as MessageReplies;
|
||||
if(replies) {
|
||||
this.appMessagesManager.getDiscussionMessage(this.peerId, mid).then(result => {
|
||||
const message = result.messages[0];
|
||||
this.chat.appImManager.setInnerPeer(-replies.channel_id, (message as MyMessage).mid, 'discussion');
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//this.log('chatInner click:', target);
|
||||
const isVideoComponentElement = target.tagName == 'SPAN';
|
||||
/* if(isVideoComponentElement) {
|
||||
|
@ -634,7 +649,12 @@ export default class ChatBubbles {
|
|||
if(isReplyClick && bubble.classList.contains('is-reply')/* || bubble.classList.contains('forwarded') */) {
|
||||
this.replyFollowHistory.push(+bubble.dataset.mid);
|
||||
let originalMessageId = +bubble.getAttribute('data-original-mid');
|
||||
this.chat.appImManager.setInnerPeer(this.peerId, originalMessageId);
|
||||
|
||||
if(this.chat.type === 'discussion') {
|
||||
this.chat.appImManager.setPeer(this.peerId, originalMessageId);
|
||||
} else {
|
||||
this.chat.appImManager.setInnerPeer(this.peerId, originalMessageId);
|
||||
}
|
||||
//this.chat.setPeer(this.peerId, originalMessageId);
|
||||
}
|
||||
} else if(target.tagName == 'IMG' && target.parentElement.tagName == "AVATAR-ELEMENT") {
|
||||
|
@ -673,14 +693,15 @@ export default class ChatBubbles {
|
|||
const mid = this.replyFollowHistory.pop();
|
||||
this.chat.setPeer(this.peerId, mid);
|
||||
} else {
|
||||
const dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0];
|
||||
this.chat.setPeer(this.peerId/* , dialog.top_message */);
|
||||
// const dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0];
|
||||
|
||||
if(dialog) {
|
||||
this.chat.setPeer(this.peerId/* , dialog.top_message */);
|
||||
} else {
|
||||
this.log('will scroll down 3');
|
||||
this.scroll.scrollTop = this.scroll.scrollHeight;
|
||||
}
|
||||
// if(dialog) {
|
||||
// this.chat.setPeer(this.peerId/* , dialog.top_message */);
|
||||
// } else {
|
||||
// this.log('will scroll down 3');
|
||||
// this.scroll.scrollTop = this.scroll.scrollHeight;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -745,10 +766,11 @@ export default class ChatBubbles {
|
|||
|
||||
if(this.scrolledAllDown) return;
|
||||
|
||||
let dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0];
|
||||
//let dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0];
|
||||
const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);
|
||||
|
||||
// if scroll down after search
|
||||
if(!top && (!dialog || history.indexOf(dialog.top_message) === -1)/* && this.chat.type == 'chat' */) {
|
||||
if(!top && history.indexOf(historyStorage.maxId) === -1/* && this.chat.type == 'chat' */) {
|
||||
this.log('Will load more (down) history by maxId:', history[history.length - 1], history);
|
||||
/* false && */this.getHistory(history[history.length - 1], false, true, undefined, justLoad);
|
||||
}
|
||||
|
@ -833,14 +855,15 @@ export default class ChatBubbles {
|
|||
}
|
||||
}
|
||||
|
||||
public updateUnreadByDialog(dialog: Dialog) {
|
||||
let maxId = this.peerId == rootScope.myId ? dialog.read_inbox_max_id : dialog.read_outbox_max_id;
|
||||
public updateUnreadByDialog() {
|
||||
const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);
|
||||
const maxId = this.peerId == rootScope.myId ? historyStorage.readMaxId : historyStorage.readOutboxMaxId;
|
||||
|
||||
///////this.log('updateUnreadByDialog', maxId, dialog, this.unreadOut);
|
||||
|
||||
for(let msgId of this.unreadOut) {
|
||||
for(const msgId of this.unreadOut) {
|
||||
if(msgId > 0 && msgId <= maxId) {
|
||||
let bubble = this.bubbles[msgId];
|
||||
const bubble = this.bubbles[msgId];
|
||||
if(bubble) {
|
||||
bubble.classList.remove('is-sent');
|
||||
bubble.classList.add('is-read');
|
||||
|
@ -884,6 +907,14 @@ export default class ChatBubbles {
|
|||
return;
|
||||
}
|
||||
|
||||
if(this.chat.threadId) {
|
||||
mids = mids.filter(mid => {
|
||||
const message = this.chat.getMessage(mid);
|
||||
const replyTo = message.reply_to as MessageReplyHeader;
|
||||
return replyTo && (replyTo.reply_to_top_id || replyTo.reply_to_msg_id) === this.chat.threadId;
|
||||
});
|
||||
}
|
||||
|
||||
mids = mids.filter(mid => !this.bubbles[mid]);
|
||||
mids.forEach((mid: number) => {
|
||||
const message = this.chat.getMessage(mid);
|
||||
|
@ -993,7 +1024,7 @@ export default class ChatBubbles {
|
|||
}
|
||||
|
||||
public destroy() {
|
||||
this.chat.log.error('Bubbles destroying');
|
||||
//this.chat.log.error('Bubbles destroying');
|
||||
|
||||
this.scrollable.onScrolledTop = this.scrollable.onScrolledBottom = this.scrollable.onAdditionalScroll = null;
|
||||
|
||||
|
@ -1068,15 +1099,16 @@ export default class ChatBubbles {
|
|||
|
||||
const samePeer = this.peerId == peerId;
|
||||
|
||||
const dialog = this.appMessagesManager.getDialogByPeerId(peerId)[0] || null;
|
||||
let topMessage = lastMsgId <= 0 ? lastMsgId : dialog?.top_message ?? 0;
|
||||
const historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);
|
||||
let topMessage = lastMsgId <= 0 ? lastMsgId : historyStorage.maxId ?? 0;
|
||||
const isTarget = lastMsgId !== undefined;
|
||||
|
||||
if(!isTarget && dialog) {
|
||||
if(dialog.unread_count && !samePeer) {
|
||||
lastMsgId = dialog.read_inbox_max_id;
|
||||
if(!isTarget && historyStorage.maxId) {
|
||||
const isUnread = this.appMessagesManager.isHistoryUnread(peerId, this.chat.threadId);
|
||||
if(/* dialog.unread_count */isUnread && !samePeer) {
|
||||
lastMsgId = historyStorage.readMaxId;
|
||||
} else {
|
||||
lastMsgId = dialog.top_message;
|
||||
lastMsgId = historyStorage.maxId;
|
||||
//lastMsgID = topMessage;
|
||||
}
|
||||
}
|
||||
|
@ -1090,7 +1122,7 @@ export default class ChatBubbles {
|
|||
this.scrollable.scrollIntoView(mounted.bubble);
|
||||
this.highlightBubble(mounted.bubble);
|
||||
this.chat.setListenerResult('setPeer', lastMsgId, false);
|
||||
} else if(dialog && !isJump) {
|
||||
} else if(historyStorage.maxId && !isJump) {
|
||||
//this.log('will scroll down', this.scroll.scrollTop, this.scroll.scrollHeight);
|
||||
this.scroll.scrollTop = this.scroll.scrollHeight;
|
||||
this.chat.setListenerResult('setPeer', lastMsgId, true);
|
||||
|
@ -1108,7 +1140,7 @@ export default class ChatBubbles {
|
|||
this.replyFollowHistory.length = 0;
|
||||
}
|
||||
|
||||
this.log('setPeer peerId:', this.peerId, dialog, lastMsgId, topMessage);
|
||||
this.log('setPeer peerId:', this.peerId, historyStorage, lastMsgId, topMessage);
|
||||
|
||||
// add last message, bc in getHistory will load < max_id
|
||||
const additionMsgId = isJump || this.chat.type !== 'chat' ? 0 : topMessage;
|
||||
|
@ -1187,14 +1219,14 @@ export default class ChatBubbles {
|
|||
this.lazyLoadQueue.unlock();
|
||||
|
||||
//if(dialog && lastMsgID && lastMsgID != topMessage && (this.bubbles[lastMsgID] || this.firstUnreadBubble)) {
|
||||
if(dialog && (isTarget || isJump)) {
|
||||
if(historyStorage.maxId && (isTarget || isJump)) {
|
||||
if(this.scrollable.scrollLocked) {
|
||||
clearTimeout(this.scrollable.scrollLocked);
|
||||
this.scrollable.scrollLocked = 0;
|
||||
}
|
||||
|
||||
const fromUp = maxBubbleId > 0 && (maxBubbleId < lastMsgId || lastMsgId < 0);
|
||||
const forwardingUnread = dialog.read_inbox_max_id == lastMsgId && !isTarget;
|
||||
const forwardingUnread = historyStorage.readMaxId === lastMsgId && !isTarget;
|
||||
if(!fromUp && (samePeer || forwardingUnread)) {
|
||||
this.scrollable.scrollTop = this.scrollable.scrollHeight;
|
||||
} else if(fromUp/* && (samePeer || forwardingUnread) */) {
|
||||
|
@ -1228,12 +1260,15 @@ export default class ChatBubbles {
|
|||
this.log('scrolledAllDown:', this.scrolledAllDown);
|
||||
|
||||
//if(!this.unreaded.length && dialog) { // lol
|
||||
if(this.scrolledAllDown && dialog) { // lol
|
||||
this.appMessagesManager.readHistory(peerId, dialog.top_message);
|
||||
if(this.scrolledAllDown && historyStorage.maxId) { // lol
|
||||
this.appMessagesManager.readHistory(peerId, historyStorage.maxId);
|
||||
}
|
||||
|
||||
if(dialog?.pFlags?.unread_mark) {
|
||||
this.appMessagesManager.markDialogUnread(peerId, true);
|
||||
if(this.chat.type === 'chat') {
|
||||
const dialog = this.appMessagesManager.getDialogByPeerId(peerId)[0];
|
||||
if(dialog?.pFlags.unread_mark) {
|
||||
this.appMessagesManager.markDialogUnread(peerId, true);
|
||||
}
|
||||
}
|
||||
|
||||
this.chatInner.classList.remove('disable-hover', 'is-scrolling'); // warning, performance!
|
||||
|
@ -1653,6 +1688,8 @@ export default class ChatBubbles {
|
|||
bubble.classList.add(status);
|
||||
}
|
||||
|
||||
const withReplyFooter = message.replies && message.replies.pFlags.comments;
|
||||
|
||||
const isOut = our && (!message.fwd_from || this.peerId != rootScope.myId);
|
||||
let nameContainer = bubbleContainer;
|
||||
|
||||
|
@ -1693,7 +1730,7 @@ export default class ChatBubbles {
|
|||
const photo = this.appPhotosManager.getPhoto(message.id);
|
||||
//if(photo._ == 'photoEmpty') break;
|
||||
this.log('will wrap pending photo:', pending, message, photo);
|
||||
const withTail = !isAndroid && !message.message;
|
||||
const withTail = !isAndroid && !message.message && !withReplyFooter;
|
||||
if(withTail) bubble.classList.add('with-media-tail');
|
||||
wrapPhoto({
|
||||
photo, message,
|
||||
|
@ -1714,7 +1751,7 @@ export default class ChatBubbles {
|
|||
let doc = this.appDocsManager.getDoc(message.id);
|
||||
//if(doc._ == 'documentEmpty') break;
|
||||
this.log('will wrap pending video:', pending, message, doc);
|
||||
const withTail = !isAndroid && !isApple && doc.type != 'round' && !message.message;
|
||||
const withTail = !isAndroid && !isApple && doc.type != 'round' && !message.message && !withReplyFooter;
|
||||
if(withTail) bubble.classList.add('with-media-tail');
|
||||
wrapVideo({
|
||||
doc,
|
||||
|
@ -1789,7 +1826,7 @@ export default class ChatBubbles {
|
|||
break;
|
||||
}
|
||||
|
||||
const withTail = !isAndroid && !message.message;
|
||||
const withTail = !isAndroid && !message.message && !withReplyFooter;
|
||||
if(withTail) bubble.classList.add('with-media-tail');
|
||||
wrapPhoto({
|
||||
photo,
|
||||
|
@ -1917,7 +1954,7 @@ export default class ChatBubbles {
|
|||
box.append(quote);
|
||||
|
||||
//bubble.prepend(box);
|
||||
bubbleContainer.prepend(timeSpan, box);
|
||||
messageDiv.insertBefore(box, messageDiv.lastElementChild);
|
||||
|
||||
//this.log('night running', bubble.scrollHeight);
|
||||
|
||||
|
@ -1973,7 +2010,7 @@ export default class ChatBubbles {
|
|||
chat: this.chat
|
||||
});
|
||||
} else {
|
||||
const withTail = !isAndroid && !isApple && doc.type != 'round' && !message.message;
|
||||
const withTail = !isAndroid && !isApple && doc.type != 'round' && !message.message && withReplyFooter;
|
||||
if(withTail) bubble.classList.add('with-media-tail');
|
||||
wrapVideo({
|
||||
doc,
|
||||
|
@ -2123,7 +2160,7 @@ export default class ChatBubbles {
|
|||
nameContainer.append(nameDiv);
|
||||
}
|
||||
} else {
|
||||
if(message.reply_to_mid) {
|
||||
if(message.reply_to_mid && message.reply_to_mid !== this.chat.threadId) {
|
||||
let originalMessage = this.chat.type === 'scheduled' ? this.appMessagesManager.getMessageByPeer(this.peerId, message.reply_to_mid) : this.chat.getMessage(message.reply_to_mid);
|
||||
let originalPeerTitle = this.appPeersManager.getPeerTitle(originalMessage.fromId || originalMessage.fwdFromId, true) || '';
|
||||
|
||||
|
@ -2186,7 +2223,7 @@ export default class ChatBubbles {
|
|||
|
||||
if(savedFrom) {
|
||||
const goto = document.createElement('div');
|
||||
goto.classList.add('bubble-beside-button', 'goto-original', 'tgico-next');
|
||||
goto.classList.add('bubble-beside-button', 'goto-original', 'tgico-arrow-next');
|
||||
bubbleContainer.append(goto);
|
||||
bubble.dataset.savedFrom = savedFrom;
|
||||
bubble.classList.add('with-beside-button');
|
||||
|
@ -2201,6 +2238,15 @@ export default class ChatBubbles {
|
|||
this.bubbleGroups.updateGroupByMessageId(message.mid);
|
||||
}
|
||||
|
||||
if(withReplyFooter) {
|
||||
MessageRender.renderReplies({
|
||||
bubble,
|
||||
bubbleContainer,
|
||||
message,
|
||||
messageDiv
|
||||
});
|
||||
}
|
||||
|
||||
return bubble;
|
||||
}
|
||||
|
||||
|
@ -2229,14 +2275,9 @@ export default class ChatBubbles {
|
|||
}
|
||||
} */
|
||||
|
||||
let dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0];
|
||||
if(dialog && dialog.top_message) {
|
||||
for(let mid of history) {
|
||||
if(mid == dialog.top_message) {
|
||||
this.scrolledAllDown = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);
|
||||
if(history.includes(historyStorage.maxId)) {
|
||||
this.scrolledAllDown = true;
|
||||
}
|
||||
|
||||
//console.time('appImManager render history');
|
||||
|
@ -2332,21 +2373,12 @@ export default class ChatBubbles {
|
|||
|
||||
public requestHistory(maxId: number, loadCount: number, backLimit: number) {
|
||||
//const middleware = this.getMiddleware();
|
||||
if(this.chat.type === 'chat') {
|
||||
return this.appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit);
|
||||
if(this.chat.type === 'chat' || this.chat.type === 'discussion') {
|
||||
return this.appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit, this.chat.threadId);
|
||||
} else if(this.chat.type === 'pinned') {
|
||||
const promise = this.appMessagesManager.getSearch(this.peerId, '', {_: 'inputMessagesFilterPinned'}, maxId, loadCount, 0, backLimit)
|
||||
.then(value => ({history: value.history.map(m => m.mid)}));
|
||||
|
||||
/* if(maxId) {
|
||||
promise.then(result => {
|
||||
if(!middleware()) return;
|
||||
|
||||
this.messagesCount = result.count;
|
||||
this.chat.topbar.setTitle();
|
||||
});
|
||||
} */
|
||||
|
||||
return promise;
|
||||
} else if(this.chat.type === 'scheduled') {
|
||||
return this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => {
|
||||
|
@ -2403,7 +2435,7 @@ export default class ChatBubbles {
|
|||
|
||||
let additionMsgIds: number[];
|
||||
if(additionMsgId && !isBackLimit) {
|
||||
const historyStorage = this.appMessagesManager.getHistoryStorage(peerId);
|
||||
const historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);
|
||||
if(historyStorage.history.length < loadCount) {
|
||||
additionMsgIds = historyStorage.history.slice();
|
||||
|
||||
|
@ -2554,8 +2586,8 @@ export default class ChatBubbles {
|
|||
|
||||
// preload more
|
||||
//if(!isFirstMessageRender) {
|
||||
if(this.chat.type === 'chat') {
|
||||
const storage = this.appMessagesManager.getHistoryStorage(peerId);
|
||||
if(this.chat.type === 'chat' || this.chat.type === 'discussion') {
|
||||
const storage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);
|
||||
const isMaxIdInHistory = storage.history.indexOf(maxId) !== -1;
|
||||
if(isMaxIdInHistory) { // * otherwise it is a search or jump
|
||||
setTimeout(() => {
|
||||
|
@ -2578,10 +2610,11 @@ export default class ChatBubbles {
|
|||
return;
|
||||
}
|
||||
|
||||
let dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0];
|
||||
if(!dialog?.unread_count) return;
|
||||
const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);
|
||||
const isUnread = this.appMessagesManager.isHistoryUnread(this.peerId, this.chat.threadId);
|
||||
if(!isUnread) return;
|
||||
|
||||
let maxId = dialog.read_inbox_max_id;
|
||||
let maxId = historyStorage.readMaxId;
|
||||
maxId = Object.keys(this.bubbles).filter(mid => !this.bubbles[mid].classList.contains('is-out')).map(i => +i).sort((a, b) => a - b).find(i => i > maxId);
|
||||
|
||||
if(maxId && this.bubbles[maxId]) {
|
||||
|
@ -2591,7 +2624,7 @@ export default class ChatBubbles {
|
|||
this.firstUnreadBubble = null;
|
||||
}
|
||||
|
||||
if(maxId != dialog.top_message) {
|
||||
if(maxId !== historyStorage.maxId) {
|
||||
bubble.classList.add('is-first-unread');
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ export default class Chat extends EventListenerBase<{
|
|||
public contextMenu: ChatContextMenu;
|
||||
|
||||
public peerId = 0;
|
||||
public threadId: number;
|
||||
public setPeerPromise: Promise<void>;
|
||||
public peerChanged: boolean;
|
||||
|
||||
|
@ -55,7 +56,7 @@ export default class Chat extends EventListenerBase<{
|
|||
// * constructor end
|
||||
|
||||
this.log = logger('CHAT', LogLevels.log | LogLevels.warn | LogLevels.debug | LogLevels.error);
|
||||
this.log.error('Chat construction');
|
||||
//this.log.error('Chat construction');
|
||||
|
||||
this.container.append(this.backgroundEl);
|
||||
this.appImManager.chatsContainer.append(this.container);
|
||||
|
@ -95,6 +96,9 @@ export default class Chat extends EventListenerBase<{
|
|||
} else if(this.type === 'scheduled') {
|
||||
this.bubbles.constructScheduledHelpers();
|
||||
this.input.constructPeerHelpers();
|
||||
} else if(this.type === 'discussion') {
|
||||
this.bubbles.constructPeerHelpers();
|
||||
this.input.constructPeerHelpers();
|
||||
}
|
||||
|
||||
this.container.classList.add('type-' + this.type);
|
||||
|
@ -102,7 +106,7 @@ export default class Chat extends EventListenerBase<{
|
|||
}
|
||||
|
||||
public destroy() {
|
||||
const perf = performance.now();
|
||||
//const perf = performance.now();
|
||||
|
||||
this.topbar.destroy();
|
||||
this.bubbles.destroy();
|
||||
|
@ -116,7 +120,7 @@ export default class Chat extends EventListenerBase<{
|
|||
|
||||
this.container.remove();
|
||||
|
||||
this.log.error('Chat destroy time:', performance.now() - perf);
|
||||
//this.log.error('Chat destroy time:', performance.now() - perf);
|
||||
}
|
||||
|
||||
public cleanup() {
|
||||
|
@ -132,6 +136,11 @@ export default class Chat extends EventListenerBase<{
|
|||
this.init = null;
|
||||
}
|
||||
|
||||
if(this.type === 'discussion' && !this.threadId) {
|
||||
this.threadId = lastMsgId;
|
||||
lastMsgId = 0;
|
||||
}
|
||||
|
||||
//console.time('appImManager setPeer');
|
||||
//console.time('appImManager setPeer pre promise');
|
||||
////console.time('appImManager: pre render start');
|
||||
|
@ -178,9 +187,9 @@ export default class Chat extends EventListenerBase<{
|
|||
|
||||
appSidebarRight.sharedMediaTab.setLoadMutex(this.setPeerPromise);
|
||||
appSidebarRight.sharedMediaTab.loadSidebarMedia(true);
|
||||
this.setPeerPromise.then(() => {
|
||||
/* this.setPeerPromise.then(() => {
|
||||
appSidebarRight.sharedMediaTab.loadSidebarMedia(false);
|
||||
});
|
||||
}); */
|
||||
|
||||
return this.setPeerPromise;
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ export default class ChatInput {
|
|||
private scrollOffsetTop = 0;
|
||||
private scrollDiff = 0;
|
||||
|
||||
private helperType: Exclude<ChatInputHelperType, 'webpage'>;
|
||||
public helperType: Exclude<ChatInputHelperType, 'webpage'>;
|
||||
private helperFunc: () => void;
|
||||
private helperWaitingForward: boolean;
|
||||
|
||||
|
@ -382,7 +382,8 @@ export default class ChatInput {
|
|||
duration,
|
||||
waveform: result.waveform,
|
||||
objectURL: result.url,
|
||||
replyToMsgId: this.replyToMsgId
|
||||
replyToMsgId: this.replyToMsgId,
|
||||
threadId: this.chat.threadId
|
||||
});
|
||||
|
||||
this.onMessageSent(false, true);
|
||||
|
@ -455,7 +456,7 @@ export default class ChatInput {
|
|||
}
|
||||
|
||||
public destroy() {
|
||||
this.chat.log.error('Input destroying');
|
||||
//this.chat.log.error('Input destroying');
|
||||
|
||||
emoticonsDropdown.events.onOpen.findAndSplice(f => f == this.onEmoticonsOpen);
|
||||
emoticonsDropdown.events.onClose.findAndSplice(f => f == this.onEmoticonsClose);
|
||||
|
@ -1108,6 +1109,7 @@ export default class ChatInput {
|
|||
} else {
|
||||
this.appMessagesManager.sendText(this.chat.peerId, str, {
|
||||
replyToMsgId: this.replyToMsgId,
|
||||
threadId: this.chat.threadId,
|
||||
noWebPage: this.noWebPage,
|
||||
webPage: this.willSendWebPage,
|
||||
scheduleDate: this.scheduleDate,
|
||||
|
@ -1151,6 +1153,7 @@ export default class ChatInput {
|
|||
this.appMessagesManager.sendFile(this.chat.peerId, document, {
|
||||
isMedia: true,
|
||||
replyToMsgId: this.replyToMsgId,
|
||||
threadId: this.chat.threadId,
|
||||
silent: this.sendSilent,
|
||||
scheduleDate: this.scheduleDate
|
||||
});
|
||||
|
@ -1235,7 +1238,7 @@ export default class ChatInput {
|
|||
this.willSendWebPage = null;
|
||||
}
|
||||
|
||||
this.replyToMsgId = undefined;
|
||||
this.replyToMsgId = this.chat.threadId;
|
||||
this.forwardingMids.length = 0;
|
||||
this.forwardingFromPeerId = 0;
|
||||
this.editMsgId = undefined;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { getFullDate } from "../../helpers/date";
|
||||
import { formatNumber } from "../../helpers/number";
|
||||
import { MessageReplies } from "../../layer";
|
||||
import appPeersManager from "../../lib/appManagers/appPeersManager";
|
||||
import RichTextProcessor from "../../lib/richtextprocessor";
|
||||
import { ripple } from "../ripple";
|
||||
import Chat from "./chat";
|
||||
|
||||
type Message = any;
|
||||
|
@ -58,4 +61,56 @@ export namespace MessageRender {
|
|||
|
||||
return timeSpan;
|
||||
};
|
||||
|
||||
export const renderReplies = ({bubble, bubbleContainer, message, messageDiv}: {
|
||||
bubble: HTMLElement,
|
||||
bubbleContainer: HTMLElement,
|
||||
message: any,
|
||||
messageDiv: HTMLElement
|
||||
}) => {
|
||||
const replies = message.replies as MessageReplies;
|
||||
const isFooter = !bubble.classList.contains('sticker') && !bubble.classList.contains('emoji-big');
|
||||
if(isFooter) {
|
||||
const container = document.createElement('div');
|
||||
container.classList.add('replies-footer');
|
||||
|
||||
let leftHTML = '', lastStyle = '';
|
||||
if(replies?.recent_repliers) {
|
||||
leftHTML += '<div class="replies-footer-avatars">'
|
||||
/**
|
||||
* MACOS, ANDROID - без реверса
|
||||
* WINDOWS DESKTOP - реверс
|
||||
* все приложения накладывают аватарку первую на вторую, а в макете зато вторая на первую, ЛОЛ!
|
||||
*/
|
||||
let l: string[] = [];
|
||||
replies.recent_repliers/* .slice().reverse() */.forEach((peer, idx) => {
|
||||
lastStyle = idx == 0 ? '' : `style="transform: translateX(-${idx * 12}px);"`;
|
||||
l.push(`<avatar-element class="avatar-32" dialog="0" peer="${appPeersManager.getPeerId(peer)}" ${lastStyle}></avatar-element>`);
|
||||
});
|
||||
leftHTML += l.reverse().join('') + '</div>';
|
||||
} else {
|
||||
leftHTML = '<span class="tgico-comments"></span>';
|
||||
}
|
||||
|
||||
let text: string;
|
||||
if(replies?.replies) {
|
||||
text = replies.replies + ' ' + (replies.replies > 1 ? 'Comments' : 'Comment');
|
||||
} else {
|
||||
text = 'Leave a Comment';
|
||||
}
|
||||
|
||||
if(replies) {
|
||||
if(replies.read_max_id < replies.max_id) {
|
||||
container.classList.add('is-unread');
|
||||
}
|
||||
}
|
||||
|
||||
container.innerHTML = `${leftHTML}<span class="replies-footer-text" ${lastStyle}>${text}</span><span class="tgico-next"></span>`;
|
||||
|
||||
const rippleContainer = document.createElement('div');
|
||||
container.append(rippleContainer);
|
||||
ripple(rippleContainer);
|
||||
bubbleContainer.prepend(container);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -304,9 +304,7 @@ export default class ChatSelection {
|
|||
this.cancelSelection();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if(this.chat.type === 'chat' || this.chat.type === 'pinned') {
|
||||
} else {
|
||||
this.selectionForwardBtn = Button('btn-primary btn-transparent selection-container-forward', {icon: 'forward'});
|
||||
this.selectionForwardBtn.append('Forward');
|
||||
this.listenerSetter.add(this.selectionForwardBtn, 'click', () => {
|
||||
|
|
|
@ -50,7 +50,7 @@ export default class ChatTopbar {
|
|||
}
|
||||
|
||||
public construct() {
|
||||
this.chat.log.error('Topbar construction');
|
||||
//this.chat.log.error('Topbar construction');
|
||||
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('sidebar-header', 'topbar');
|
||||
|
@ -320,7 +320,7 @@ export default class ChatTopbar {
|
|||
};
|
||||
|
||||
public destroy() {
|
||||
this.chat.log.error('Topbar destroying');
|
||||
//this.chat.log.error('Topbar destroying');
|
||||
|
||||
this.listenerSetter.removeAll();
|
||||
mediaSizes.removeListener('changeScreen', this.onChangeScreen);
|
||||
|
@ -386,7 +386,6 @@ export default class ChatTopbar {
|
|||
public setTitle(count?: number) {
|
||||
let title = '';
|
||||
if(this.chat.type === 'pinned') {
|
||||
//title = !count ? 'Pinned Messages' : (count === 1 ? 'Pinned Message' : (count + ' Pinned Messages'));
|
||||
title = [count > 1 ? count : false, 'Pinned Messages'].filter(Boolean).join(' ');
|
||||
|
||||
if(count === undefined) {
|
||||
|
@ -408,10 +407,8 @@ export default class ChatTopbar {
|
|||
}
|
||||
} else if(this.chat.type === 'scheduled') {
|
||||
if(this.peerId === rootScope.myId) {
|
||||
//title = !count ? 'Reminders' : (count === 1 ? 'Reminder' : (count + ' Reminders'));
|
||||
title = [count > 1 ? count : false, 'Reminders'].filter(Boolean).join(' ');
|
||||
} else {
|
||||
//title = !count ? 'Scheduled Messages' : (count === 1 ? 'Scheduled Message' : (count + ' Scheduled Messages'));
|
||||
title = [count > 1 ? count : false, 'Scheduled Messages'].filter(Boolean).join(' ');
|
||||
}
|
||||
|
||||
|
@ -420,6 +417,17 @@ export default class ChatTopbar {
|
|||
this.setTitle(mids.length);
|
||||
});
|
||||
}
|
||||
} else if(this.chat.type === 'discussion') {
|
||||
title = [count > 1 ? count : false, 'Comments'].filter(Boolean).join(' ');
|
||||
|
||||
if(count === undefined) {
|
||||
Promise.all([
|
||||
this.appMessagesManager.getHistory(this.peerId, 0, 1, 0, this.chat.threadId),
|
||||
Promise.resolve()
|
||||
]).then(() => {
|
||||
this.setTitle(this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId).count);
|
||||
});
|
||||
}
|
||||
} else if(this.chat.type === 'chat') {
|
||||
if(this.peerId == rootScope.myId) title = 'Saved Messages';
|
||||
else title = this.appPeersManager.getPeerTitle(this.peerId);
|
||||
|
|
|
@ -531,7 +531,7 @@ export default class PollElement extends HTMLElement {
|
|||
*/
|
||||
results.recent_voters/* .slice().reverse() */.forEach((userId, idx) => {
|
||||
const style = idx == 0 ? '' : `style="transform: translateX(-${idx * 3}px);"`;
|
||||
html += `<avatar-element dialog="0" peer="${userId}" ${style}></avatar-element>`;
|
||||
html += `<avatar-element class="avatar-18" dialog="0" peer="${userId}" ${style}></avatar-element>`;
|
||||
});
|
||||
this.avatarsDiv.innerHTML = html;
|
||||
}
|
||||
|
|
|
@ -241,10 +241,16 @@ export default class PopupCreatePoll extends PopupElement {
|
|||
//console.log('Will try to create poll:', inputMediaPoll);
|
||||
|
||||
this.chat.appMessagesManager.sendOther(this.chat.peerId, inputMediaPoll, {
|
||||
threadId: this.chat.threadId,
|
||||
replyToMsgId: this.chat.input.replyToMsgId,
|
||||
scheduleDate: this.chat.input.scheduleDate,
|
||||
silent: this.chat.input.sendSilent
|
||||
});
|
||||
|
||||
if(this.chat.input.helperType === 'reply') {
|
||||
this.chat.input.clearHelper();
|
||||
}
|
||||
|
||||
this.chat.input.onMessageSent(false, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ export default class PopupDatePicker extends PopupElement {
|
|||
noTitle: true,
|
||||
minDate: Date,
|
||||
maxDate: Date
|
||||
withTime: true
|
||||
withTime: true,
|
||||
showOverflowMonths: true
|
||||
}> & PopupOptions = {}) {
|
||||
super('popup-date-picker', options.noButtons ? [] : [{
|
||||
text: 'CANCEL',
|
||||
|
@ -242,7 +243,7 @@ export default class PopupDatePicker extends PopupElement {
|
|||
});
|
||||
}
|
||||
|
||||
this.btnConfirm.innerText = 'Send ' + dayStr + ' at ' + ('00' + this.hoursInputField.value).slice(-2) + ':' + ('00' + this.minutesInputField.value).slice(-2);
|
||||
this.btnConfirm.firstChild.nodeValue = 'Send ' + dayStr + ' at ' + ('00' + this.hoursInputField.value).slice(-2) + ':' + ('00' + this.minutesInputField.value).slice(-2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,6 +252,21 @@ export default class PopupDatePicker extends PopupElement {
|
|||
this.title.innerText = splitted[0] + ', ' + splitted[1] + ' ' + splitted[2];
|
||||
}
|
||||
|
||||
private renderElement(disabled: boolean, innerText = '') {
|
||||
const el = document.createElement('button');
|
||||
el.classList.add('btn-icon', 'date-picker-month-date');
|
||||
|
||||
if(disabled) {
|
||||
el.setAttribute('disabled', 'true');
|
||||
}
|
||||
|
||||
if(innerText) {
|
||||
el.innerText = innerText;
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
public setMonth() {
|
||||
this.monthTitle.innerText = months[this.selectedMonth.getMonth()] + ' ' + this.selectedMonth.getFullYear();
|
||||
|
||||
|
@ -263,8 +279,9 @@ export default class PopupDatePicker extends PopupElement {
|
|||
|
||||
const days = ['M', 'T', 'W', 'T', 'F', 'S', 'S'];
|
||||
this.month.append(...days.map(s => {
|
||||
const el = document.createElement('span');
|
||||
el.innerText = s;
|
||||
const el = this.renderElement(true, s);
|
||||
el.classList.remove('date-picker-month-date');
|
||||
el.classList.add('date-picker-month-day');
|
||||
return el;
|
||||
}));
|
||||
|
||||
|
@ -274,23 +291,24 @@ export default class PopupDatePicker extends PopupElement {
|
|||
let dayIndex = firstDate.getDay() - 1;
|
||||
if(dayIndex == -1) dayIndex = days.length - 1;
|
||||
|
||||
const clonedDate = new Date(firstDate.getTime());
|
||||
clonedDate.setDate(clonedDate.getDate() - dayIndex - 1);
|
||||
|
||||
// Padding first week
|
||||
for(let i = 0; i < dayIndex; ++i) {
|
||||
const el = document.createElement('span');
|
||||
this.month.append(el);
|
||||
if(this.options.showOverflowMonths) {
|
||||
clonedDate.setDate(clonedDate.getDate() + 1);
|
||||
this.month.append(this.renderElement(true, '' + clonedDate.getDate()));
|
||||
} else {
|
||||
this.month.append(this.renderElement(true));
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
const date = firstDate.getDate();
|
||||
const el = document.createElement('button');
|
||||
el.classList.add('btn-icon');
|
||||
el.innerText = '' + date;
|
||||
const el = this.renderElement(firstDate > this.maxDate || firstDate < this.minDate, '' + date);
|
||||
el.dataset.timestamp = '' + firstDate.getTime();
|
||||
|
||||
if(firstDate > this.maxDate || firstDate < this.minDate) {
|
||||
el.setAttribute('disabled', 'true');
|
||||
}
|
||||
|
||||
if(firstDate.getTime() === this.selectedDate.getTime()) {
|
||||
this.selectedEl = el;
|
||||
el.classList.add('active');
|
||||
|
@ -301,6 +319,14 @@ export default class PopupDatePicker extends PopupElement {
|
|||
firstDate.setDate(date + 1);
|
||||
} while(firstDate.getDate() !== 1);
|
||||
|
||||
const remainder = this.month.childElementCount % 7;
|
||||
if(this.options.showOverflowMonths && remainder) {
|
||||
for(let i = remainder; i < 7; ++i) {
|
||||
this.month.append(this.renderElement(true, '' + firstDate.getDate()));
|
||||
firstDate.setDate(firstDate.getDate() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.container.classList.toggle('is-max-lines', (this.month.childElementCount / 7) > 6);
|
||||
|
||||
this.monthsContainer.append(this.month);
|
||||
|
|
|
@ -11,7 +11,7 @@ export default class PopupDeleteMessages {
|
|||
const firstName = appPeersManager.getPeerTitle(peerId, false, true);
|
||||
|
||||
mids = mids.slice();
|
||||
const callback = (revoke: boolean) => {
|
||||
const callback = (revoke?: true) => {
|
||||
onConfirm && onConfirm();
|
||||
if(type === 'scheduled') {
|
||||
appMessagesManager.deleteScheduledMessages(peerId, mids);
|
||||
|
@ -28,13 +28,13 @@ export default class PopupDeleteMessages {
|
|||
buttons = [{
|
||||
text: 'DELETE',
|
||||
isDanger: true,
|
||||
callback: () => callback(false)
|
||||
callback: () => callback()
|
||||
}];
|
||||
} else {
|
||||
buttons = [{
|
||||
text: 'DELETE JUST FOR ME',
|
||||
isDanger: true,
|
||||
callback: () => callback(false)
|
||||
callback: () => callback()
|
||||
}];
|
||||
|
||||
if(peerId > 0) {
|
||||
|
|
|
@ -162,20 +162,26 @@ export default class PopupNewMedia extends PopupElement {
|
|||
this.chat.appMessagesManager.sendAlbum(peerId, w.sendFileDetails.map(d => d.file), Object.assign({
|
||||
caption,
|
||||
replyToMsgId: input.replyToMsgId,
|
||||
threadId: this.chat.threadId,
|
||||
isMedia: willAttach.isMedia,
|
||||
silent,
|
||||
scheduleDate
|
||||
}, w));
|
||||
|
||||
caption = undefined;
|
||||
input.replyToMsgId = undefined;
|
||||
input.replyToMsgId = this.chat.threadId;
|
||||
}
|
||||
} else {
|
||||
if(caption) {
|
||||
if(willAttach.sendFileDetails.length > 1) {
|
||||
this.chat.appMessagesManager.sendText(peerId, caption, {replyToMsgId: input.replyToMsgId, silent, scheduleDate});
|
||||
this.chat.appMessagesManager.sendText(peerId, caption, {
|
||||
replyToMsgId: input.replyToMsgId,
|
||||
threadId: this.chat.threadId,
|
||||
silent,
|
||||
scheduleDate
|
||||
});
|
||||
caption = '';
|
||||
input.replyToMsgId = undefined;
|
||||
//input.replyToMsgId = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,14 +191,16 @@ export default class PopupNewMedia extends PopupElement {
|
|||
isMedia: willAttach.isMedia,
|
||||
caption,
|
||||
replyToMsgId: input.replyToMsgId,
|
||||
threadId: this.chat.threadId,
|
||||
silent,
|
||||
scheduleDate
|
||||
}, params));
|
||||
|
||||
caption = '';
|
||||
input.replyToMsgId = undefined;
|
||||
return promise;
|
||||
});
|
||||
|
||||
input.replyToMsgId = this.chat.threadId;
|
||||
}
|
||||
|
||||
//Promise.all(promises);
|
||||
|
|
|
@ -21,7 +21,8 @@ export default class PopupSchedule extends PopupDatePicker {
|
|||
date.setDate(date.getDate() - 1);
|
||||
return date;
|
||||
})(),
|
||||
withTime: true
|
||||
withTime: true,
|
||||
showOverflowMonths: true
|
||||
});
|
||||
|
||||
this.element.classList.add('popup-schedule');
|
||||
|
|
|
@ -29,7 +29,7 @@ export default class AppAddMembersTab implements SliderTab {
|
|||
return;
|
||||
}
|
||||
|
||||
this.nextBtn.classList.remove('tgico-next');
|
||||
this.nextBtn.classList.remove('tgico-arrow-next');
|
||||
this.nextBtn.disabled = true;
|
||||
putPreloader(this.nextBtn);
|
||||
this.selector.freezed = true;
|
||||
|
@ -61,7 +61,7 @@ export default class AppAddMembersTab implements SliderTab {
|
|||
|
||||
this.nextBtn.innerHTML = '';
|
||||
this.nextBtn.disabled = false;
|
||||
this.nextBtn.classList.add('tgico-next');
|
||||
this.nextBtn.classList.add('tgico-arrow-next');
|
||||
this.nextBtn.classList.toggle('is-visible', skippable);
|
||||
|
||||
appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.addMembers);
|
||||
|
|
|
@ -351,7 +351,7 @@ export function wrapDocument({message, withTime, uploading, fontWeight}: {
|
|||
}): HTMLElement {
|
||||
if(!fontWeight) fontWeight = 500;
|
||||
|
||||
const doc = message.media.document;
|
||||
const doc = message.media.document || message.media.webpage.document;
|
||||
if(doc.type == 'audio' || doc.type == 'voice') {
|
||||
const audioElement = new AudioElement();
|
||||
audioElement.setAttribute('message-id', '' + message.mid);
|
||||
|
|
|
@ -455,9 +455,9 @@ export class AppImManager {
|
|||
appSidebarRight.sharedMediaTab.loadSidebarMedia(true);
|
||||
appSidebarRight.sharedMediaTab.fillProfileElements();
|
||||
|
||||
setTimeout(() => {
|
||||
/* setTimeout(() => {
|
||||
appSidebarRight.sharedMediaTab.loadSidebarMedia(false);
|
||||
});
|
||||
}); */
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -4,7 +4,7 @@ import { tsNow } from "../../helpers/date";
|
|||
import { copy, defineNotNumerableProperties, getObjectKeysAndSort } from "../../helpers/object";
|
||||
import { randomLong } from "../../helpers/random";
|
||||
import { splitStringByLength, limitSymbols } from "../../helpers/string";
|
||||
import { Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputNotifyPeer, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessagesDialogs, MessagesFilter, MessagesMessages, MessagesPeerDialogs, MethodDeclMap, NotifyPeer, PhotoSize, SendMessageAction, Update } from "../../layer";
|
||||
import { Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputNotifyPeer, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MessagesPeerDialogs, MethodDeclMap, NotifyPeer, PhotoSize, SendMessageAction, Update } from "../../layer";
|
||||
import { InvokeApiOptions } from "../../types";
|
||||
import { langPack } from "../langPack";
|
||||
import { logger, LogLevels } from "../logger";
|
||||
|
@ -43,8 +43,11 @@ export type HistoryStorage = {
|
|||
history: number[],
|
||||
pending: number[],
|
||||
|
||||
maxId?: number,
|
||||
readPromise?: Promise<boolean>,
|
||||
readMaxId?: number,
|
||||
readOutboxMaxId?: number,
|
||||
|
||||
maxOutId?: number,
|
||||
reply_markup?: any
|
||||
};
|
||||
|
@ -89,6 +92,11 @@ export class AppMessagesManager {
|
|||
public historiesStorage: {
|
||||
[peerId: string]: HistoryStorage
|
||||
} = {};
|
||||
public threadsStorage: {
|
||||
[peerId: string]: {
|
||||
[threadId: string]: HistoryStorage
|
||||
}
|
||||
} = {};
|
||||
public searchesStorage: {
|
||||
[peerId: string]: Partial<{
|
||||
[inputFilter in MyInputMessagesFilter]: {
|
||||
|
@ -386,6 +394,7 @@ export class AppMessagesManager {
|
|||
public sendText(peerId: number, text: string, options: Partial<{
|
||||
entities: any[],
|
||||
replyToMsgId: number,
|
||||
threadId: number,
|
||||
viaBotId: number,
|
||||
queryId: string,
|
||||
resultId: string,
|
||||
|
@ -462,7 +471,7 @@ export class AppMessagesManager {
|
|||
date: options.scheduleDate || (tsNow(true) + serverTimeManager.serverTimeOffset),
|
||||
message: text,
|
||||
random_id: randomIdS,
|
||||
reply_to: {reply_to_msg_id: replyToMsgId},
|
||||
reply_to: this.generateReplyHeader(options.replyToMsgId, options.threadId),
|
||||
via_bot_id: options.viaBotId,
|
||||
reply_markup: options.reply_markup,
|
||||
entities: entities,
|
||||
|
@ -579,6 +588,7 @@ export class AppMessagesManager {
|
|||
isMedia: true,
|
||||
|
||||
replyToMsgId: number,
|
||||
threadId: number,
|
||||
caption: string,
|
||||
entities: MessageEntity[],
|
||||
width: number,
|
||||
|
@ -785,7 +795,7 @@ export class AppMessagesManager {
|
|||
document: file
|
||||
} : media,
|
||||
random_id: randomIdS,
|
||||
reply_to: {reply_to_msg_id: replyToMsgId},
|
||||
reply_to: this.generateReplyHeader(options.replyToMsgId, options.threadId),
|
||||
views: asChannel && 1,
|
||||
pending: true
|
||||
};
|
||||
|
@ -923,6 +933,7 @@ export class AppMessagesManager {
|
|||
isMedia: true,
|
||||
entities: MessageEntity[],
|
||||
replyToMsgId: number,
|
||||
threadId: number,
|
||||
caption: string,
|
||||
sendFileDetails: Partial<{
|
||||
duration: number,
|
||||
|
@ -958,13 +969,15 @@ export class AppMessagesManager {
|
|||
isMedia: options.isMedia,
|
||||
scheduleDate: options.scheduleDate,
|
||||
silent: options.silent,
|
||||
replyToMsgId,
|
||||
threadId: options.threadId,
|
||||
...details
|
||||
};
|
||||
|
||||
if(idx === 0) {
|
||||
o.caption = caption;
|
||||
o.entities = entities;
|
||||
o.replyToMsgId = replyToMsgId;
|
||||
//o.replyToMsgId = replyToMsgId;
|
||||
}
|
||||
|
||||
return this.sendFile(peerId, file, o).message;
|
||||
|
@ -1058,6 +1071,7 @@ export class AppMessagesManager {
|
|||
|
||||
public sendOther(peerId: number, inputMedia: any, options: Partial<{
|
||||
replyToMsgId: number,
|
||||
threadId: number,
|
||||
viaBotId: number,
|
||||
reply_markup: any,
|
||||
clearDraft: true,
|
||||
|
@ -1181,7 +1195,7 @@ export class AppMessagesManager {
|
|||
message: '',
|
||||
media,
|
||||
random_id: randomIdS,
|
||||
reply_to: {reply_to_msg_id: replyToMsgId},
|
||||
reply_to: this.generateReplyHeader(options.replyToMsgId, options.threadId),
|
||||
via_bot_id: options.viaBotId,
|
||||
reply_markup: options.reply_markup,
|
||||
views: asChannel && 1,
|
||||
|
@ -1299,6 +1313,19 @@ export class AppMessagesManager {
|
|||
}
|
||||
}
|
||||
|
||||
private generateReplyHeader(replyToMsgId: number, replyToTopId?: number) {
|
||||
const header = {
|
||||
_: 'messageReplyHeader',
|
||||
reply_to_msg_id: replyToMsgId,
|
||||
} as MessageReplyHeader;
|
||||
|
||||
if(replyToTopId && replyToTopId !== replyToMsgId) {
|
||||
header.reply_to_top_id = replyToTopId;
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
private setDialogIndexByMessage(dialog: MTDialog.dialog, message: MyMessage) {
|
||||
if(!dialog.pFlags.pinned || !dialog.index) {
|
||||
dialog.index = this.dialogsStorage.generateDialogIndex(message.date);
|
||||
|
@ -1309,6 +1336,9 @@ export class AppMessagesManager {
|
|||
const dialog = this.getDialogByPeerId(message.peerId)[0];
|
||||
if(dialog) {
|
||||
dialog.top_message = message.mid;
|
||||
|
||||
const historyStorage = this.getHistoryStorage(message.peerId);
|
||||
historyStorage.maxId = message.mid;
|
||||
|
||||
this.setDialogIndexByMessage(dialog, message);
|
||||
|
||||
|
@ -1436,6 +1466,11 @@ export class AppMessagesManager {
|
|||
});
|
||||
}
|
||||
|
||||
public isHistoryUnread(peerId: number, threadId?: number) {
|
||||
const historyStorage = this.getHistoryStorage(peerId, threadId);
|
||||
return (peerId > 0 ? Math.max(historyStorage.readMaxId, historyStorage.readOutboxMaxId) : historyStorage.readMaxId) < historyStorage.maxId;
|
||||
}
|
||||
|
||||
public getTopMessages(limit: number, folderId: number): Promise<number> {
|
||||
const dialogs = this.dialogsStorage.getFolder(folderId);
|
||||
let offsetId = 0;
|
||||
|
@ -1492,7 +1527,7 @@ export class AppMessagesManager {
|
|||
(dialogsResult.dialogs as Dialog[]).forEachReverse(dialog => {
|
||||
//const d = Object.assign({}, dialog);
|
||||
// ! нужно передавать folderId, так как по папке != 0 нет свойства folder_id
|
||||
this.saveConversation(dialog, folderId);
|
||||
this.saveConversation(dialog, dialog.folder_id ?? folderId);
|
||||
|
||||
/* if(dialog.peerId == -1213511294) {
|
||||
this.log.error('lun bot', folderId, d);
|
||||
|
@ -1505,9 +1540,11 @@ export class AppMessagesManager {
|
|||
|
||||
// ! это может случиться, если запрос идёт не по папке 0, а по 1. почему-то read'ов нет
|
||||
// ! в итоге, чтобы получить 1 диалог, делается первый запрос по папке 0, потом запрос для архивных по папке 1, и потом ещё перезагрузка архивного диалога
|
||||
if(!dialog.read_inbox_max_id && !dialog.read_outbox_max_id) {
|
||||
if(!this.getLocalMessageId(dialog.read_inbox_max_id) && !this.getLocalMessageId(dialog.read_outbox_max_id)) {
|
||||
noIdsDialogs[dialog.peerId] = dialog;
|
||||
|
||||
this.log.error('noIdsDialogs', dialog);
|
||||
|
||||
/* if(dialog.peerId == -1213511294) {
|
||||
this.log.error('lun bot', folderId);
|
||||
} */
|
||||
|
@ -1622,7 +1659,7 @@ export class AppMessagesManager {
|
|||
|
||||
public getMessageById(messageId: number) {
|
||||
for(const peerId in this.messagesStorageByPeerId) {
|
||||
if(appPeersManager.isChannel(-+peerId)) {
|
||||
if(appPeersManager.isChannel(+peerId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1849,7 +1886,7 @@ export class AppMessagesManager {
|
|||
public generateMessageId(messageId: number, temp = false) {
|
||||
const q = 0xFFFFFFFF;
|
||||
const num = temp ? ++this.tempNum : 0;
|
||||
if(messageId > q) {
|
||||
if(messageId >= q) {
|
||||
if(temp) {
|
||||
return messageId + (num & 0xFFFF);
|
||||
}
|
||||
|
@ -1865,7 +1902,7 @@ export class AppMessagesManager {
|
|||
*/
|
||||
public getLocalMessageId(messageId: number) {
|
||||
const q = 0xFFFFFFFF;
|
||||
if(messageId < q) {
|
||||
if(messageId <= q) {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
|
@ -1928,9 +1965,17 @@ export class AppMessagesManager {
|
|||
}
|
||||
// this.log(dT(), 'msg unread', mid, apiMessage.pFlags.out, dialog && dialog[apiMessage.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id'])
|
||||
|
||||
if(message.reply_to && message.reply_to.reply_to_msg_id) {
|
||||
//message.reply_to_mid = message.reply_to.reply_to_msg_id;
|
||||
message.reply_to_mid = this.generateMessageId(message.reply_to.reply_to_msg_id);
|
||||
if(message.reply_to) {
|
||||
if(message.reply_to.reply_to_msg_id) {
|
||||
message.reply_to.reply_to_msg_id = message.reply_to_mid = this.generateMessageId(message.reply_to.reply_to_msg_id);
|
||||
}
|
||||
|
||||
if(message.reply_to.reply_to_top_id) message.reply_to.reply_to_top_id = this.generateMessageId(message.reply_to.reply_to_top_id);
|
||||
}
|
||||
|
||||
if(message.replies) {
|
||||
if(message.replies.max_id) message.replies.max_id = this.generateMessageId(message.replies.max_id);
|
||||
if(message.replies.read_max_id) message.replies.read_max_id = this.generateMessageId(message.replies.read_max_id);
|
||||
}
|
||||
|
||||
const overwriting = !!message.peerId;
|
||||
|
@ -1945,7 +1990,8 @@ export class AppMessagesManager {
|
|||
if(message.peerId == myId/* && !message.from_id && !message.fwd_from */) {
|
||||
message.fromId = message.fwd_from ? (message.fwd_from.from_id ? appPeersManager.getPeerId(message.fwd_from.from_id) : 0) : myId;
|
||||
} else {
|
||||
message.fromId = message.pFlags.post || (!message.pFlags.out && !message.from_id) ? peerId : appPeersManager.getPeerId(message.from_id);
|
||||
//message.fromId = message.pFlags.post || (!message.pFlags.out && !message.from_id) ? peerId : appPeersManager.getPeerId(message.from_id);
|
||||
message.fromId = message.pFlags.post || !message.from_id ? peerId : appPeersManager.getPeerId(message.from_id);
|
||||
}
|
||||
|
||||
const fwdHeader = message.fwd_from;
|
||||
|
@ -2449,6 +2495,7 @@ export class AppMessagesManager {
|
|||
if(!topMessage
|
||||
|| (this.getMessageByPeer(peerId, topPendingMessage) as MyMessage).date > (this.getMessageByPeer(peerId, topMessage) as MyMessage).date) {
|
||||
dialog.top_message = topMessage = topPendingMessage;
|
||||
this.getHistoryStorage(peerId).maxId = topPendingMessage;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2546,14 +2593,15 @@ export class AppMessagesManager {
|
|||
}
|
||||
}
|
||||
|
||||
const wasDialogBefore = this.getDialogByPeerId(peerId)[0];
|
||||
|
||||
dialog.top_message = mid;
|
||||
dialog.read_inbox_max_id = this.generateMessageId(dialog.read_inbox_max_id);
|
||||
dialog.read_outbox_max_id = this.generateMessageId(dialog.read_outbox_max_id);
|
||||
dialog.read_inbox_max_id = wasDialogBefore && !dialog.read_inbox_max_id ? wasDialogBefore.read_inbox_max_id : this.generateMessageId(dialog.read_inbox_max_id);
|
||||
dialog.read_outbox_max_id = wasDialogBefore && !dialog.read_outbox_max_id ? wasDialogBefore.read_outbox_max_id : this.generateMessageId(dialog.read_outbox_max_id);
|
||||
|
||||
if(!dialog.hasOwnProperty('folder_id')) {
|
||||
if(dialog._ == 'dialog') {
|
||||
// ! СЛОЖНО ! СМОТРИ В getTopMessages
|
||||
const wasDialogBefore = this.getDialogByPeerId(peerId)[0];
|
||||
dialog.folder_id = wasDialogBefore ? wasDialogBefore.folder_id : folderId;
|
||||
}/* else if(dialog._ == 'dialogFolder') {
|
||||
dialog.folder_id = dialog.folder.id;
|
||||
|
@ -2562,12 +2610,9 @@ export class AppMessagesManager {
|
|||
|
||||
dialog.peerId = peerId;
|
||||
|
||||
this.dialogsStorage.generateIndexForDialog(dialog);
|
||||
this.dialogsStorage.pushDialog(dialog, message.date);
|
||||
|
||||
// Because we saved message without dialog present
|
||||
if(message.mid > 0) {
|
||||
if(message.mid > dialog[message.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id']) message.pFlags.unread = true;
|
||||
if(mid > 0) {
|
||||
if(mid > dialog[message.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id']) message.pFlags.unread = true;
|
||||
else delete message.pFlags.unread;
|
||||
}
|
||||
|
||||
|
@ -2584,13 +2629,16 @@ export class AppMessagesManager {
|
|||
historyStorage[mid > 0 ? 'history' : 'pending'].push(mid);
|
||||
}
|
||||
|
||||
historyStorage.maxId = mid;
|
||||
historyStorage.readMaxId = dialog.read_inbox_max_id;
|
||||
historyStorage.readOutboxMaxId = dialog.read_outbox_max_id;
|
||||
|
||||
if(channelId && dialog.pts) {
|
||||
apiUpdatesManager.addChannelState(channelId, dialog.pts);
|
||||
}
|
||||
|
||||
//if(this.filtersStorage.inited) {
|
||||
//this.filtersStorage.processDialog(dialog);
|
||||
//}
|
||||
this.dialogsStorage.generateIndexForDialog(dialog);
|
||||
this.dialogsStorage.pushDialog(dialog, message.date);
|
||||
}
|
||||
|
||||
public mergeReplyKeyboard(historyStorage: HistoryStorage, message: any) {
|
||||
|
@ -2679,9 +2727,24 @@ export class AppMessagesManager {
|
|||
});
|
||||
}
|
||||
|
||||
public getSearchNew({peerId, query, inputFilter, maxId, limit, offsetRate, backLimit, threadId}: {
|
||||
peerId: number,
|
||||
maxId: number,
|
||||
limit?: number,
|
||||
offsetRate?: number,
|
||||
backLimit?: number,
|
||||
threadId?: number,
|
||||
query?: string,
|
||||
inputFilter?: {
|
||||
_: MyInputMessagesFilter
|
||||
},
|
||||
}) {
|
||||
return this.getSearch(peerId, query, inputFilter, maxId, limit, offsetRate, backLimit, threadId);
|
||||
}
|
||||
|
||||
public getSearch(peerId = 0, query: string = '', inputFilter: {
|
||||
_: MyInputMessagesFilter
|
||||
} = {_: 'inputMessagesFilterEmpty'}, maxId: number, limit = 20, offsetRate = 0, backLimit = 0): Promise<{
|
||||
} = {_: 'inputMessagesFilterEmpty'}, maxId: number, limit = 20, offsetRate = 0, backLimit = 0, threadId = 0): Promise<{
|
||||
count: number,
|
||||
next_rate: number,
|
||||
offset_id_offset: number,
|
||||
|
@ -2704,7 +2767,7 @@ export class AppMessagesManager {
|
|||
};
|
||||
|
||||
// * костыль для limit 1, если нужно и получить сообщение, и узнать количество сообщений
|
||||
if(peerId && !backLimit && !maxId && !query && limit !== 1/* && inputFilter._ !== 'inputMessagesFilterPinned' */) {
|
||||
if(peerId && !backLimit && !maxId && !query && limit !== 1 && !threadId/* && inputFilter._ !== 'inputMessagesFilterPinned' */) {
|
||||
storage = beta ?
|
||||
this.getSearchStorage(peerId, inputFilter._) :
|
||||
this.getHistoryStorage(peerId);
|
||||
|
@ -2860,19 +2923,20 @@ export class AppMessagesManager {
|
|||
add_offset: backLimit ? -backLimit : 0,
|
||||
max_id: 0,
|
||||
min_id: 0,
|
||||
hash: 0
|
||||
hash: 0,
|
||||
top_msg_id: threadId
|
||||
}, {
|
||||
//timeout: APITIMEOUT,
|
||||
noErrorBox: true
|
||||
});
|
||||
} else {
|
||||
var offsetDate = 0;
|
||||
var offsetPeerId = 0;
|
||||
var offsetId = 0;
|
||||
var offsetMessage = maxId && this.getMessageByPeer(peerId, maxId);
|
||||
//var offsetDate = 0;
|
||||
let offsetPeerId = 0;
|
||||
let offsetId = 0;
|
||||
let offsetMessage = maxId && this.getMessageByPeer(peerId, maxId);
|
||||
|
||||
if(offsetMessage && offsetMessage.date) {
|
||||
offsetDate = offsetMessage.date + serverTimeManager.serverTimeOffset;
|
||||
//offsetDate = offsetMessage.date + serverTimeManager.serverTimeOffset;
|
||||
offsetId = offsetMessage.id;
|
||||
offsetPeerId = this.getMessagePeer(offsetMessage);
|
||||
}
|
||||
|
@ -2885,7 +2949,7 @@ export class AppMessagesManager {
|
|||
offset_rate: offsetRate,
|
||||
offset_peer: appPeersManager.getInputPeerById(offsetPeerId),
|
||||
offset_id: offsetId,
|
||||
limit
|
||||
limit,
|
||||
}, {
|
||||
//timeout: APITIMEOUT,
|
||||
noErrorBox: true
|
||||
|
@ -2930,6 +2994,25 @@ export class AppMessagesManager {
|
|||
});
|
||||
}
|
||||
|
||||
public getDiscussionMessage(peerId: number, mid: number) {
|
||||
return apiManager.invokeApi('messages.getDiscussionMessage', {
|
||||
peer: appPeersManager.getInputPeerById(peerId),
|
||||
msg_id: this.getLocalMessageId(mid)
|
||||
}).then(result => {
|
||||
appChatsManager.saveApiChats(result.chats);
|
||||
appUsersManager.saveApiUsers(result.users);
|
||||
this.saveMessages(result.messages);
|
||||
|
||||
const message = result.messages[0] as MyMessage;
|
||||
const historyStorage = this.getHistoryStorage(message.peerId, message.mid);
|
||||
historyStorage.maxId = this.generateMessageId(result.max_id) || 0;
|
||||
historyStorage.readMaxId = this.generateMessageId(result.read_inbox_max_id) || 0;
|
||||
historyStorage.readOutboxMaxId = this.generateMessageId(result.read_outbox_max_id) || 0;
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
handleNewMessages = () => {
|
||||
clearTimeout(this.newMessagesHandlePromise);
|
||||
this.newMessagesHandlePromise = 0;
|
||||
|
@ -2972,12 +3055,12 @@ export class AppMessagesManager {
|
|||
}
|
||||
}
|
||||
|
||||
public deleteMessages(peerId: number, mids: number[], revoke: boolean) {
|
||||
public deleteMessages(peerId: number, mids: number[], revoke?: true) {
|
||||
let promise: Promise<any>;
|
||||
|
||||
mids = mids.map(mid => this.getLocalMessageId(mid));
|
||||
|
||||
if(peerId < 0 && appPeersManager.isChannel(-peerId)) {
|
||||
if(peerId < 0 && appPeersManager.isChannel(peerId)) {
|
||||
const channelId = -peerId;
|
||||
const channel = appChatsManager.getChat(channelId);
|
||||
if(!channel.pFlags.creator && !(channel.pFlags.editor && channel.pFlags.megagroup)) {
|
||||
|
@ -3015,7 +3098,7 @@ export class AppMessagesManager {
|
|||
});
|
||||
} else {
|
||||
promise = apiManager.invokeApi('messages.deleteMessages', {
|
||||
revoke: revoke || undefined,
|
||||
revoke,
|
||||
id: mids
|
||||
}).then((affectedMessages) => {
|
||||
apiUpdatesManager.processUpdateMessage({
|
||||
|
@ -3035,24 +3118,10 @@ export class AppMessagesManager {
|
|||
|
||||
public readHistory(peerId: number, maxId = 0) {
|
||||
// console.trace('start read')
|
||||
if(!this.isHistoryUnread(peerId)) return Promise.resolve(true);
|
||||
|
||||
const isChannel = appPeersManager.isChannel(peerId);
|
||||
const historyStorage = this.getHistoryStorage(peerId);
|
||||
const foundDialog = this.getDialogByPeerId(peerId)[0];
|
||||
|
||||
if(!foundDialog || !foundDialog.unread_count) {
|
||||
if(!historyStorage.history.length) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
let foundUnread = !!historyStorage.history.find(messageId => {
|
||||
const message = this.getMessagesStorage(peerId)[messageId];
|
||||
return message && !message.pFlags.out && message.pFlags.unread;
|
||||
});
|
||||
|
||||
if(!foundUnread) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
if(!historyStorage.readMaxId || maxId > historyStorage.readMaxId) {
|
||||
historyStorage.readMaxId = maxId;
|
||||
|
@ -3066,7 +3135,7 @@ export class AppMessagesManager {
|
|||
if(isChannel) {
|
||||
apiPromise = apiManager.invokeApi('channels.readHistory', {
|
||||
channel: appChatsManager.getChannelInput(-peerId),
|
||||
max_id: maxId
|
||||
max_id: this.getLocalMessageId(maxId)
|
||||
}).then((res) => {
|
||||
apiUpdatesManager.processUpdateMessage({
|
||||
_: 'updateShort',
|
||||
|
@ -3082,7 +3151,7 @@ export class AppMessagesManager {
|
|||
} else {
|
||||
apiPromise = apiManager.invokeApi('messages.readHistory', {
|
||||
peer: appPeersManager.getInputPeerById(peerId),
|
||||
max_id: maxId
|
||||
max_id: this.getLocalMessageId(maxId)
|
||||
}).then((affectedMessages) => {
|
||||
apiUpdatesManager.processUpdateMessage({
|
||||
_: 'updateShort',
|
||||
|
@ -3111,8 +3180,6 @@ export class AppMessagesManager {
|
|||
|
||||
if(historyStorage.readMaxId > maxId) {
|
||||
this.readHistory(peerId, historyStorage.readMaxId);
|
||||
} else {
|
||||
delete historyStorage.readMaxId;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -3152,7 +3219,13 @@ export class AppMessagesManager {
|
|||
}
|
||||
}
|
||||
|
||||
public getHistoryStorage(peerId: number) {
|
||||
public getHistoryStorage(peerId: number, threadId?: number) {
|
||||
if(threadId) {
|
||||
threadId = this.getLocalMessageId(threadId);
|
||||
if(!this.threadsStorage[peerId]) this.threadsStorage[peerId] = {};
|
||||
return this.threadsStorage[peerId][threadId] ?? (this.threadsStorage[peerId][threadId] = {count: null, history: [], pending: []});
|
||||
}
|
||||
|
||||
return this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {count: null, history: [], pending: []});
|
||||
}
|
||||
|
||||
|
@ -3427,7 +3500,6 @@ export class AppMessagesManager {
|
|||
case 'updateEditChannelMessage': {
|
||||
const message = update.message as MyMessage;
|
||||
const peerId = this.getMessagePeer(message);
|
||||
//const mid = message.id;
|
||||
const mid = this.generateMessageId(message.id);
|
||||
const storage = this.getMessagesStorage(peerId);
|
||||
if(storage[mid] === undefined) {
|
||||
|
@ -3456,22 +3528,7 @@ export class AppMessagesManager {
|
|||
mid
|
||||
});
|
||||
|
||||
const groupId = (message as Message.message).grouped_id;
|
||||
/* if(this.pinnedMessagesStorage[peerId]) {
|
||||
let pinnedMid: number;
|
||||
if(groupId) {
|
||||
const mids = this.getMidsByAlbum(groupId);
|
||||
pinnedMid = mids.find(mid => this.pinnedMessagesStorage[peerId] == mid);
|
||||
} else if(this.pinnedMessagesStorage[peerId] == mid) {
|
||||
pinnedMid = mid;
|
||||
}
|
||||
|
||||
if(pinnedMid) {
|
||||
rootScope.broadcast('peer_pinned_message', peerId);
|
||||
}
|
||||
} */
|
||||
|
||||
if(isTopMessage || groupId) {
|
||||
if(isTopMessage || (message as Message.message).grouped_id) {
|
||||
const updatedDialogs: {[peerId: number]: Dialog} = {};
|
||||
updatedDialogs[peerId] = dialog;
|
||||
rootScope.broadcast('dialogs_multiupdate', updatedDialogs);
|
||||
|
@ -3480,27 +3537,34 @@ export class AppMessagesManager {
|
|||
break;
|
||||
}
|
||||
|
||||
case 'updateReadChannelDiscussionInbox':
|
||||
case 'updateReadChannelDiscussionOutbox':
|
||||
case 'updateReadHistoryInbox':
|
||||
case 'updateReadHistoryOutbox':
|
||||
case 'updateReadChannelInbox':
|
||||
case 'updateReadChannelOutbox': {
|
||||
const channelId: number = (update as Update.updateReadChannelInbox).channel_id;
|
||||
//const maxId = update.max_id;
|
||||
const maxId = this.generateMessageId(update.max_id);
|
||||
const channelId = (update as Update.updateReadChannelInbox).channel_id;
|
||||
const maxId = this.generateMessageId((update as Update.updateReadChannelInbox).max_id || (update as Update.updateReadChannelDiscussionInbox).read_max_id);
|
||||
const threadId = this.generateMessageId((update as Update.updateReadChannelDiscussionInbox).top_msg_id);
|
||||
const peerId = channelId ? -channelId : appPeersManager.getPeerId((update as Update.updateReadHistoryInbox).peer);
|
||||
const isOut = update._ == 'updateReadHistoryOutbox' || update._ == 'updateReadChannelOutbox' ? true : undefined;
|
||||
|
||||
const isOut = update._ === 'updateReadHistoryOutbox' || update._ === 'updateReadChannelOutbox' || update._ === 'updateReadChannelDiscussionOutbox' ? true : undefined;
|
||||
|
||||
const storage = this.getMessagesStorage(peerId);
|
||||
const history = getObjectKeysAndSort(storage, 'desc');
|
||||
const foundDialog = this.getDialogByPeerId(peerId)[0];
|
||||
const history = getObjectKeysAndSort(this.getMessagesStorage(peerId), 'desc');
|
||||
const stillUnreadCount = (update as Update.updateReadChannelInbox).still_unread_count;
|
||||
let newUnreadCount = 0;
|
||||
let foundAffected = false;
|
||||
|
||||
//this.log.warn(dT(), 'read', peerId, isOut ? 'out' : 'in', maxId)
|
||||
|
||||
const historyStorage = this.getHistoryStorage(peerId, threadId);
|
||||
|
||||
if(peerId > 0 && isOut) {
|
||||
appUsersManager.forceUserOnline(peerId);
|
||||
}
|
||||
|
||||
const storage = this.getMessagesStorage(peerId);
|
||||
for(let i = 0, length = history.length; i < length; i++) {
|
||||
const messageId = history[i];
|
||||
if(messageId > maxId) {
|
||||
|
@ -3508,9 +3572,6 @@ export class AppMessagesManager {
|
|||
}
|
||||
|
||||
const message = storage[messageId];
|
||||
if(!message) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(message.pFlags.out != isOut) {
|
||||
continue;
|
||||
|
@ -3519,6 +3580,13 @@ export class AppMessagesManager {
|
|||
if(!message.pFlags.unread) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(threadId) {
|
||||
const replyTo = message.reply_to as MessageReplyHeader;
|
||||
if(!replyTo || (replyTo.reply_to_top_id || replyTo.reply_to_msg_id) !== threadId) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// this.log.warn('read', messageId, message.pFlags.unread, message)
|
||||
if(message.pFlags.unread) {
|
||||
|
@ -3527,29 +3595,31 @@ export class AppMessagesManager {
|
|||
foundAffected = true;
|
||||
}
|
||||
|
||||
if(!message.pFlags.out) {
|
||||
if(foundDialog) {
|
||||
newUnreadCount = --foundDialog.unread_count;
|
||||
}
|
||||
if(!message.pFlags.out && !threadId && stillUnreadCount === undefined) {
|
||||
newUnreadCount = --foundDialog.unread_count;
|
||||
//NotificationsManager.cancel('msg' + messageId); // warning
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(foundDialog) {
|
||||
if(!isOut && newUnreadCount && foundDialog.top_message <= maxId) {
|
||||
newUnreadCount = foundDialog.unread_count = 0;
|
||||
if(isOut) historyStorage.readOutboxMaxId = maxId;
|
||||
else historyStorage.readMaxId = maxId;
|
||||
|
||||
if(!threadId && foundDialog) {
|
||||
if(isOut) foundDialog.read_outbox_max_id = maxId;
|
||||
else foundDialog.read_inbox_max_id = maxId;
|
||||
|
||||
if(!isOut) {
|
||||
if(newUnreadCount < 0 || !this.isHistoryUnread(peerId)) {
|
||||
foundDialog.unread_count = 0;
|
||||
} else if(newUnreadCount && foundDialog.top_message > maxId) {
|
||||
foundDialog.unread_count = newUnreadCount;
|
||||
}
|
||||
}
|
||||
|
||||
foundDialog[isOut ? 'read_outbox_max_id' : 'read_inbox_max_id'] = maxId;
|
||||
|
||||
rootScope.broadcast('dialog_unread', {peerId});
|
||||
}
|
||||
|
||||
// need be commented for read out messages
|
||||
//if(newUnreadCount != 0 || !isOut) { // fix 16.11.2019 (maybe not)
|
||||
//////////this.log.warn(dT(), 'cnt', peerId, newUnreadCount, isOut, foundDialog, update, foundAffected);
|
||||
rootScope.broadcast('dialog_unread', {peerId, count: newUnreadCount});
|
||||
//}
|
||||
|
||||
if(foundAffected) {
|
||||
rootScope.broadcast('messages_read');
|
||||
}
|
||||
|
@ -3625,10 +3695,7 @@ export class AppMessagesManager {
|
|||
if(historyUpdated.unread) {
|
||||
foundDialog.unread_count -= historyUpdated.unread;
|
||||
|
||||
rootScope.broadcast('dialog_unread', {
|
||||
peerId,
|
||||
count: foundDialog.unread_count
|
||||
});
|
||||
rootScope.broadcast('dialog_unread', {peerId});
|
||||
}
|
||||
|
||||
if(historyUpdated.msgs[foundDialog.top_message]) {
|
||||
|
@ -4061,12 +4128,16 @@ export class AppMessagesManager {
|
|||
});
|
||||
}
|
||||
|
||||
public getHistory(peerId: number, maxId = 0, limit: number, backLimit?: number) {
|
||||
public getHistory(peerId: number, maxId = 0, limit: number, backLimit?: number, threadId?: number) {
|
||||
if(threadId) {
|
||||
threadId = this.getLocalMessageId(threadId);
|
||||
}
|
||||
|
||||
if(this.migratedFromTo[peerId]) {
|
||||
peerId = this.migratedFromTo[peerId];
|
||||
}
|
||||
|
||||
const historyStorage = this.getHistoryStorage(peerId);
|
||||
const historyStorage = this.getHistoryStorage(peerId, threadId);
|
||||
const unreadOffset = 0;
|
||||
const unreadSkip = false;
|
||||
|
||||
|
@ -4126,7 +4197,7 @@ export class AppMessagesManager {
|
|||
limit += backLimit;
|
||||
}
|
||||
|
||||
return this.requestHistory(reqPeerId, maxId, limit, offset).then((historyResult) => {
|
||||
return this.requestHistory(reqPeerId, maxId, limit, offset, undefined, threadId).then((historyResult) => {
|
||||
historyStorage.count = (historyResult as MessagesMessages.messagesMessagesSlice).count || historyResult.messages.length;
|
||||
if(isMigrated) {
|
||||
historyStorage.count++;
|
||||
|
@ -4150,7 +4221,7 @@ export class AppMessagesManager {
|
|||
});
|
||||
}
|
||||
|
||||
return this.fillHistoryStorage(peerId, maxId, limit, historyStorage).then(() => {
|
||||
return this.fillHistoryStorage(peerId, maxId, limit, historyStorage, threadId).then(() => {
|
||||
offset = 0;
|
||||
if(maxId > 0) {
|
||||
for(offset = 0; offset < historyStorage.history.length; offset++) {
|
||||
|
@ -4174,10 +4245,10 @@ export class AppMessagesManager {
|
|||
});
|
||||
}
|
||||
|
||||
public fillHistoryStorage(peerId: number, maxId: number, fullLimit: number, historyStorage: HistoryStorage): Promise<boolean> {
|
||||
public fillHistoryStorage(peerId: number, maxId: number, fullLimit: number, historyStorage: HistoryStorage, threadId?: number): Promise<boolean> {
|
||||
// this.log('fill history storage', peerId, maxId, fullLimit, angular.copy(historyStorage))
|
||||
const offset = (this.migratedFromTo[peerId] && !maxId) ? 1 : 0;
|
||||
return this.requestHistory(peerId, maxId, fullLimit, offset).then((historyResult) => {
|
||||
return this.requestHistory(peerId, maxId, fullLimit, offset, undefined, threadId).then((historyResult) => {
|
||||
historyStorage.count = (historyResult as MessagesMessages.messagesMessagesSlice).count || historyResult.messages.length;
|
||||
|
||||
if(!maxId && historyResult.messages.length) {
|
||||
|
@ -4228,9 +4299,9 @@ export class AppMessagesManager {
|
|||
}
|
||||
}
|
||||
|
||||
return this.fillHistoryStorage(peerId, maxId, fullLimit, historyStorage);
|
||||
return this.fillHistoryStorage(peerId, maxId, fullLimit, historyStorage, threadId);
|
||||
} else if(totalCount < historyStorage.count) {
|
||||
return this.fillHistoryStorage(peerId, maxId, fullLimit, historyStorage);
|
||||
return this.fillHistoryStorage(peerId, maxId, fullLimit, historyStorage, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4251,15 +4322,16 @@ export class AppMessagesManager {
|
|||
return result;
|
||||
}
|
||||
|
||||
public requestHistory(peerId: number, maxId: number, limit = 0, offset = 0, offsetDate = 0): Promise<Exclude<MessagesMessages, MessagesMessages.messagesMessagesNotModified>> {
|
||||
public requestHistory(peerId: number, maxId: number, limit = 0, offset = 0, offsetDate = 0, threadId = 0): Promise<Exclude<MessagesMessages, MessagesMessages.messagesMessagesNotModified>> {
|
||||
const isChannel = appPeersManager.isChannel(peerId);
|
||||
|
||||
//console.trace('requestHistory', peerId, maxId, limit, offset);
|
||||
|
||||
//rootScope.broadcast('history_request');
|
||||
|
||||
const promise = apiManager.invokeApi('messages.getHistory', {
|
||||
|
||||
const options = {
|
||||
peer: appPeersManager.getInputPeerById(peerId),
|
||||
msg_id: threadId,
|
||||
offset_id: this.getLocalMessageId(maxId) || 0,
|
||||
offset_date: offsetDate,
|
||||
add_offset: offset,
|
||||
|
@ -4267,18 +4339,16 @@ export class AppMessagesManager {
|
|||
max_id: 0,
|
||||
min_id: 0,
|
||||
hash: 0
|
||||
}, {
|
||||
};
|
||||
|
||||
const promise: ReturnType<AppMessagesManager['requestHistory']> = apiManager.invokeApi(threadId ? 'messages.getReplies' : 'messages.getHistory', options, {
|
||||
//timeout: APITIMEOUT,
|
||||
noErrorBox: true
|
||||
}) as ReturnType<AppMessagesManager['requestHistory']>;
|
||||
}) as any;
|
||||
|
||||
return promise.then((historyResult) => {
|
||||
this.log('requestHistory result:', peerId, historyResult, maxId, limit, offset);
|
||||
|
||||
/* if(historyResult._ == 'messages.messagesNotModified') {
|
||||
return historyResult as any;
|
||||
} */
|
||||
|
||||
appUsersManager.saveApiUsers(historyResult.users);
|
||||
appChatsManager.saveApiChats(historyResult.chats);
|
||||
this.saveMessages(historyResult.messages);
|
||||
|
@ -4295,47 +4365,16 @@ export class AppMessagesManager {
|
|||
}
|
||||
|
||||
// will load more history if last message is album grouped (because it can be not last item)
|
||||
const historyStorage = this.getHistoryStorage(peerId);
|
||||
const historyStorage = this.getHistoryStorage(peerId, threadId);
|
||||
// historyResult.messages: desc sorted
|
||||
if(length && (historyResult.messages[length - 1] as Message.message).grouped_id
|
||||
&& (historyStorage.history.length + historyResult.messages.length) < (historyResult as MessagesMessages.messagesMessagesSlice).count) {
|
||||
return this.requestHistory(peerId, (historyResult.messages[length - 1] as Message.message).mid, 10, 0).then((_historyResult) => {
|
||||
return this.requestHistory(peerId, (historyResult.messages[length - 1] as Message.message).mid, 10, 0, offsetDate, threadId).then((_historyResult) => {
|
||||
return historyResult;
|
||||
});
|
||||
}
|
||||
|
||||
// don't need the intro now
|
||||
/* if(peerId < 0 || !appUsersManager.isBot(peerId) || (length == limit && limit < historyResult.count)) {
|
||||
return historyResult;
|
||||
} */
|
||||
return historyResult as any;
|
||||
|
||||
/* return appProfileManager.getProfile(peerId).then((userFull: any) => {
|
||||
var description = userFull.bot_info && userFull.bot_info.description;
|
||||
if(description) {
|
||||
var messageId = this.tempId--;
|
||||
var message = {
|
||||
_: 'messageService',
|
||||
id: messageId,
|
||||
from_id: peerId,
|
||||
peer_id: appPeersManager.getOutputPeer(peerId),
|
||||
pFlags: {},
|
||||
date: tsNow(true) + serverTimeManager.serverTimeOffset,
|
||||
action: {
|
||||
_: 'messageActionBotIntro',
|
||||
description: description
|
||||
}
|
||||
}
|
||||
|
||||
this.saveMessages([message]);
|
||||
historyResult.messages.push(message);
|
||||
if(historyResult.count) {
|
||||
historyResult.count++;
|
||||
}
|
||||
}
|
||||
|
||||
return historyResult;
|
||||
}); */
|
||||
}, (error) => {
|
||||
switch (error.type) {
|
||||
case 'CHANNEL_PRIVATE':
|
||||
|
|
|
@ -20,7 +20,7 @@ type BroadcastEvents = {
|
|||
'filter_order': number[],
|
||||
|
||||
'dialog_draft': {peerId: number, draft: any, index: number},
|
||||
'dialog_unread': {peerId: number, count?: number},
|
||||
'dialog_unread': {peerId: number},
|
||||
'dialog_flush': {peerId: number},
|
||||
'dialog_drop': {peerId: number, dialog?: Dialog},
|
||||
'dialog_migrate': {migrateFrom: number, migrateTo: number},
|
||||
|
|
|
@ -107,4 +107,9 @@ avatar-element {
|
|||
--size: 32px;
|
||||
--multiplier: 1.6875;
|
||||
}
|
||||
|
||||
&.avatar-18 {
|
||||
--size: 18px;
|
||||
--multiplier: 3;
|
||||
}
|
||||
}
|
|
@ -714,7 +714,8 @@ $bubble-margin: .25rem;
|
|||
}
|
||||
|
||||
.web {
|
||||
margin-top: -6px !important;
|
||||
padding-top: 1px;
|
||||
margin: 4px 0 -5px 1px;
|
||||
// margin-bottom: 5px;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
|
@ -775,11 +776,6 @@ $bubble-margin: .25rem;
|
|||
|
||||
.web, .reply {
|
||||
font-size: .95rem;
|
||||
// margin: .25rem;
|
||||
margin: 4px 4px 0 6px;
|
||||
//padding: .25rem;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
//transition: anim(background-color);
|
||||
|
||||
/* &:hover {
|
||||
|
@ -829,9 +825,10 @@ $bubble-margin: .25rem;
|
|||
}
|
||||
|
||||
.reply {
|
||||
margin-bottom: 6px;
|
||||
margin-top: 0;
|
||||
padding: 4px;
|
||||
margin: 0 4px 6px 4px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
|
||||
&-content {
|
||||
max-width: 300px;
|
||||
|
@ -881,6 +878,7 @@ $bubble-margin: .25rem;
|
|||
line-height: 21px;
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap; // * fix spaces on line begin
|
||||
position: relative;
|
||||
|
||||
/* * {
|
||||
overflow: hidden;
|
||||
|
@ -1479,6 +1477,70 @@ $bubble-margin: .25rem;
|
|||
audio-element, poll-element {
|
||||
white-space: normal; // * fix due to .message white-space prewrap
|
||||
}
|
||||
|
||||
.replies-footer {
|
||||
height: 50px;
|
||||
border-top: 1px solid #dadce0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 .5rem;
|
||||
border-bottom-left-radius: inherit;
|
||||
border-bottom-right-radius: inherit;
|
||||
color: $color-blue;
|
||||
min-width: 15rem;
|
||||
user-select: none;
|
||||
|
||||
.tgico-comments, .tgico-next {
|
||||
font-size: 1.4375rem;
|
||||
}
|
||||
|
||||
&-text {
|
||||
font-weight: 500;
|
||||
margin-left: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-avatars {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
|
||||
avatar-element {
|
||||
border: 2px solid #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.tgico-next {
|
||||
position: absolute;
|
||||
right: .5rem;
|
||||
}
|
||||
|
||||
.rp {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
border-radius: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.is-unread {
|
||||
.replies-footer-text {
|
||||
&:after {
|
||||
content: " ";
|
||||
background-color: $color-blue;
|
||||
width: .5rem;
|
||||
height: .5rem;
|
||||
margin-left: .75rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// * fix scroll with only 1 bubble
|
||||
|
@ -1988,7 +2050,7 @@ $bubble-margin: .25rem;
|
|||
}
|
||||
|
||||
&.is-link:before {
|
||||
content: $tgico-next;
|
||||
content: $tgico-arrow-next;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 2px;
|
||||
|
@ -2251,11 +2313,7 @@ poll-element {
|
|||
}
|
||||
|
||||
avatar-element {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 1px solid #fff;
|
||||
line-height: 20px;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
|
|
@ -366,7 +366,7 @@
|
|||
.tgico-forward:before {
|
||||
content: "\e96d";
|
||||
}
|
||||
.tgico-next:before {
|
||||
.tgico-arrow-next:before {
|
||||
content: "\e96e";
|
||||
}
|
||||
.tgico-unlock:before {
|
||||
|
|
|
@ -123,7 +123,7 @@ $tgico-play: "\e96a";
|
|||
$tgico-pause: "\e96b";
|
||||
$tgico-reply: "\e96c";
|
||||
$tgico-forward: "\e96d";
|
||||
$tgico-next: "\e96e";
|
||||
$tgico-arrow-next: "\e96e";
|
||||
$tgico-unlock: "\e96f";
|
||||
$tgico-lock: "\e970";
|
||||
$tgico-data: "\e971";
|
||||
|
|
|
@ -79,15 +79,7 @@
|
|||
width: 100%;
|
||||
justify-content: center;
|
||||
|
||||
span, .btn-icon {
|
||||
// justify-self: center;
|
||||
// width: 40px;
|
||||
// height: 40px;
|
||||
// font-size: 1rem;
|
||||
// color: #707579;
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
.btn-icon {
|
||||
justify-self: center;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
|
@ -96,6 +88,14 @@
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&-date:disabled {
|
||||
color: #c2c3c4;
|
||||
}
|
||||
|
||||
.btn-icon:not(:disabled) {
|
||||
|
@ -109,4 +109,77 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup-schedule {
|
||||
.popup-header {
|
||||
justify-content: space-between;
|
||||
|
||||
.btn-icon {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.popup-close {
|
||||
color: #52585d;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-container {
|
||||
min-width: 420px;
|
||||
width: 420px;
|
||||
}
|
||||
|
||||
.date-picker {
|
||||
&-month {
|
||||
&-title {
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
margin-left: -5rem;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
&-date:disabled {
|
||||
color: #9ba3a8 !important;
|
||||
}
|
||||
|
||||
&-day {
|
||||
font-weight: bold;
|
||||
color: black !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-time {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
.input-field {
|
||||
width: 80px;
|
||||
|
||||
&-input {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
&-delimiter {
|
||||
padding: 14px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&-controls {
|
||||
.btn-icon {
|
||||
color: #2a8ee4;
|
||||
|
||||
&:disabled {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user