Browse Source

Comments alpha version

master
Eduard Kuzmenko 4 years ago
parent
commit
f966e7610f
  1. 8
      src/components/audio.ts
  2. 165
      src/components/chat/bubbles.ts
  3. 19
      src/components/chat/chat.ts
  4. 11
      src/components/chat/input.ts
  5. 55
      src/components/chat/messageRender.ts
  6. 4
      src/components/chat/selection.ts
  7. 18
      src/components/chat/topbar.ts
  8. 2
      src/components/poll.ts
  9. 6
      src/components/popups/createPoll.ts
  10. 52
      src/components/popups/datePicker.ts
  11. 6
      src/components/popups/deleteMessages.ts
  12. 16
      src/components/popups/newMedia.ts
  13. 3
      src/components/popups/schedule.ts
  14. 4
      src/components/sidebarLeft/tabs/addMembers.ts
  15. 2
      src/components/wrappers.ts
  16. 4
      src/lib/appManagers/appImManager.ts
  17. 345
      src/lib/appManagers/appMessagesManager.ts
  18. 2
      src/lib/rootScope.ts
  19. 5
      src/scss/partials/_avatar.scss
  20. 84
      src/scss/partials/_chatBubble.scss
  21. 2
      src/scss/partials/_fonts.scss
  22. 2
      src/scss/partials/_ico.scss
  23. 91
      src/scss/partials/popups/_datePicker.scss

8
src/components/audio.ts

@ -66,7 +66,7 @@ function wrapVoiceMessage(audioEl: AudioElement) {
audioEl.classList.add('is-voice'); audioEl.classList.add('is-voice');
const message = audioEl.message; 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; const isOut = message.fromId == rootScope.myId && message.peerId != rootScope.myId;
let isUnread = message && message.pFlags.media_unread; let isUnread = message && message.pFlags.media_unread;
if(isUnread) { if(isUnread) {
@ -254,7 +254,7 @@ function wrapVoiceMessage(audioEl: AudioElement) {
function wrapAudio(audioEl: AudioElement) { function wrapAudio(audioEl: AudioElement) {
const withTime = audioEl.withTime; 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; const title = doc.audioTitle || doc.file_name;
let subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : ''; let subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : '';
@ -334,7 +334,7 @@ export default class AudioElement extends HTMLElement {
this.classList.add('audio'); 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 uploading = this.message.pFlags.is_outgoing;
const durationStr = String(doc.duration | 0).toHHMMSS(true); const durationStr = String(doc.duration | 0).toHHMMSS(true);
@ -360,7 +360,7 @@ export default class AudioElement extends HTMLElement {
audioTimeDiv.innerHTML = durationStr; audioTimeDiv.innerHTML = durationStr;
const onLoad = (autoload = true) => { 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(); this.onTypeDisconnect = onTypeLoad();

165
src/components/chat/bubbles.ts

@ -37,6 +37,7 @@ import Chat from "./chat";
import ListenerSetter from "../../helpers/listenerSetter"; import ListenerSetter from "../../helpers/listenerSetter";
import PollElement from "../poll"; import PollElement from "../poll";
import AudioElement from "../audio"; import AudioElement from "../audio";
import { MessageReplies, MessageReplyHeader } from "../../layer";
const IGNORE_ACTIONS = ['messageActionHistoryClear']; const IGNORE_ACTIONS = ['messageActionHistoryClear'];
@ -104,7 +105,7 @@ export default class ChatBubbles {
public replyFollowHistory: number[] = []; 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) { 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(); this.listenerSetter = new ListenerSetter();
@ -358,10 +359,9 @@ export default class ChatBubbles {
this.listenerSetter.add(rootScope, 'dialog_unread', (e) => { this.listenerSetter.add(rootScope, 'dialog_unread', (e) => {
const info = e.detail; const info = e.detail;
const dialog = this.appMessagesManager.getDialogByPeerId(info.peerId)[0]; if(info.peerId == this.peerId) {
if(dialog?.peerId == this.peerId) {
this.chat.input.setUnreadCount(); this.chat.input.setUnreadCount();
this.updateUnreadByDialog(dialog); this.updateUnreadByDialog();
} }
}); });
@ -510,6 +510,21 @@ export default class ChatBubbles {
return; 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); //this.log('chatInner click:', target);
const isVideoComponentElement = target.tagName == 'SPAN'; const isVideoComponentElement = target.tagName == 'SPAN';
/* if(isVideoComponentElement) { /* if(isVideoComponentElement) {
@ -634,7 +649,12 @@ export default class ChatBubbles {
if(isReplyClick && bubble.classList.contains('is-reply')/* || bubble.classList.contains('forwarded') */) { if(isReplyClick && bubble.classList.contains('is-reply')/* || bubble.classList.contains('forwarded') */) {
this.replyFollowHistory.push(+bubble.dataset.mid); this.replyFollowHistory.push(+bubble.dataset.mid);
let originalMessageId = +bubble.getAttribute('data-original-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); //this.chat.setPeer(this.peerId, originalMessageId);
} }
} else if(target.tagName == 'IMG' && target.parentElement.tagName == "AVATAR-ELEMENT") { } else if(target.tagName == 'IMG' && target.parentElement.tagName == "AVATAR-ELEMENT") {
@ -673,14 +693,15 @@ export default class ChatBubbles {
const mid = this.replyFollowHistory.pop(); const mid = this.replyFollowHistory.pop();
this.chat.setPeer(this.peerId, mid); this.chat.setPeer(this.peerId, mid);
} else { } 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) { // if(dialog) {
this.chat.setPeer(this.peerId/* , dialog.top_message */); // this.chat.setPeer(this.peerId/* , dialog.top_message */);
} else { // } else {
this.log('will scroll down 3'); // this.log('will scroll down 3');
this.scroll.scrollTop = this.scroll.scrollHeight; // this.scroll.scrollTop = this.scroll.scrollHeight;
} // }
} }
} }
@ -745,10 +766,11 @@ export default class ChatBubbles {
if(this.scrolledAllDown) return; 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 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); 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); /* false && */this.getHistory(history[history.length - 1], false, true, undefined, justLoad);
} }
@ -833,14 +855,15 @@ export default class ChatBubbles {
} }
} }
public updateUnreadByDialog(dialog: Dialog) { public updateUnreadByDialog() {
let maxId = this.peerId == rootScope.myId ? dialog.read_inbox_max_id : dialog.read_outbox_max_id; 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); ///////this.log('updateUnreadByDialog', maxId, dialog, this.unreadOut);
for(let msgId of this.unreadOut) { for(const msgId of this.unreadOut) {
if(msgId > 0 && msgId <= maxId) { if(msgId > 0 && msgId <= maxId) {
let bubble = this.bubbles[msgId]; const bubble = this.bubbles[msgId];
if(bubble) { if(bubble) {
bubble.classList.remove('is-sent'); bubble.classList.remove('is-sent');
bubble.classList.add('is-read'); bubble.classList.add('is-read');
@ -884,6 +907,14 @@ export default class ChatBubbles {
return; 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 = mids.filter(mid => !this.bubbles[mid]);
mids.forEach((mid: number) => { mids.forEach((mid: number) => {
const message = this.chat.getMessage(mid); const message = this.chat.getMessage(mid);
@ -993,7 +1024,7 @@ export default class ChatBubbles {
} }
public destroy() { public destroy() {
this.chat.log.error('Bubbles destroying'); //this.chat.log.error('Bubbles destroying');
this.scrollable.onScrolledTop = this.scrollable.onScrolledBottom = this.scrollable.onAdditionalScroll = null; this.scrollable.onScrolledTop = this.scrollable.onScrolledBottom = this.scrollable.onAdditionalScroll = null;
@ -1068,15 +1099,16 @@ export default class ChatBubbles {
const samePeer = this.peerId == peerId; const samePeer = this.peerId == peerId;
const dialog = this.appMessagesManager.getDialogByPeerId(peerId)[0] || null; const historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);
let topMessage = lastMsgId <= 0 ? lastMsgId : dialog?.top_message ?? 0; let topMessage = lastMsgId <= 0 ? lastMsgId : historyStorage.maxId ?? 0;
const isTarget = lastMsgId !== undefined; const isTarget = lastMsgId !== undefined;
if(!isTarget && dialog) { if(!isTarget && historyStorage.maxId) {
if(dialog.unread_count && !samePeer) { const isUnread = this.appMessagesManager.isHistoryUnread(peerId, this.chat.threadId);
lastMsgId = dialog.read_inbox_max_id; if(/* dialog.unread_count */isUnread && !samePeer) {
lastMsgId = historyStorage.readMaxId;
} else { } else {
lastMsgId = dialog.top_message; lastMsgId = historyStorage.maxId;
//lastMsgID = topMessage; //lastMsgID = topMessage;
} }
} }
@ -1090,7 +1122,7 @@ export default class ChatBubbles {
this.scrollable.scrollIntoView(mounted.bubble); this.scrollable.scrollIntoView(mounted.bubble);
this.highlightBubble(mounted.bubble); this.highlightBubble(mounted.bubble);
this.chat.setListenerResult('setPeer', lastMsgId, false); 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.log('will scroll down', this.scroll.scrollTop, this.scroll.scrollHeight);
this.scroll.scrollTop = this.scroll.scrollHeight; this.scroll.scrollTop = this.scroll.scrollHeight;
this.chat.setListenerResult('setPeer', lastMsgId, true); this.chat.setListenerResult('setPeer', lastMsgId, true);
@ -1108,7 +1140,7 @@ export default class ChatBubbles {
this.replyFollowHistory.length = 0; 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 // add last message, bc in getHistory will load < max_id
const additionMsgId = isJump || this.chat.type !== 'chat' ? 0 : topMessage; const additionMsgId = isJump || this.chat.type !== 'chat' ? 0 : topMessage;
@ -1187,14 +1219,14 @@ export default class ChatBubbles {
this.lazyLoadQueue.unlock(); this.lazyLoadQueue.unlock();
//if(dialog && lastMsgID && lastMsgID != topMessage && (this.bubbles[lastMsgID] || this.firstUnreadBubble)) { //if(dialog && lastMsgID && lastMsgID != topMessage && (this.bubbles[lastMsgID] || this.firstUnreadBubble)) {
if(dialog && (isTarget || isJump)) { if(historyStorage.maxId && (isTarget || isJump)) {
if(this.scrollable.scrollLocked) { if(this.scrollable.scrollLocked) {
clearTimeout(this.scrollable.scrollLocked); clearTimeout(this.scrollable.scrollLocked);
this.scrollable.scrollLocked = 0; this.scrollable.scrollLocked = 0;
} }
const fromUp = maxBubbleId > 0 && (maxBubbleId < lastMsgId || lastMsgId < 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)) { if(!fromUp && (samePeer || forwardingUnread)) {
this.scrollable.scrollTop = this.scrollable.scrollHeight; this.scrollable.scrollTop = this.scrollable.scrollHeight;
} else if(fromUp/* && (samePeer || forwardingUnread) */) { } else if(fromUp/* && (samePeer || forwardingUnread) */) {
@ -1228,12 +1260,15 @@ export default class ChatBubbles {
this.log('scrolledAllDown:', this.scrolledAllDown); this.log('scrolledAllDown:', this.scrolledAllDown);
//if(!this.unreaded.length && dialog) { // lol //if(!this.unreaded.length && dialog) { // lol
if(this.scrolledAllDown && dialog) { // lol if(this.scrolledAllDown && historyStorage.maxId) { // lol
this.appMessagesManager.readHistory(peerId, dialog.top_message); this.appMessagesManager.readHistory(peerId, historyStorage.maxId);
} }
if(dialog?.pFlags?.unread_mark) { if(this.chat.type === 'chat') {
this.appMessagesManager.markDialogUnread(peerId, true); 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! this.chatInner.classList.remove('disable-hover', 'is-scrolling'); // warning, performance!
@ -1653,6 +1688,8 @@ export default class ChatBubbles {
bubble.classList.add(status); bubble.classList.add(status);
} }
const withReplyFooter = message.replies && message.replies.pFlags.comments;
const isOut = our && (!message.fwd_from || this.peerId != rootScope.myId); const isOut = our && (!message.fwd_from || this.peerId != rootScope.myId);
let nameContainer = bubbleContainer; let nameContainer = bubbleContainer;
@ -1693,7 +1730,7 @@ export default class ChatBubbles {
const photo = this.appPhotosManager.getPhoto(message.id); const photo = this.appPhotosManager.getPhoto(message.id);
//if(photo._ == 'photoEmpty') break; //if(photo._ == 'photoEmpty') break;
this.log('will wrap pending photo:', pending, message, photo); 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'); if(withTail) bubble.classList.add('with-media-tail');
wrapPhoto({ wrapPhoto({
photo, message, photo, message,
@ -1714,7 +1751,7 @@ export default class ChatBubbles {
let doc = this.appDocsManager.getDoc(message.id); let doc = this.appDocsManager.getDoc(message.id);
//if(doc._ == 'documentEmpty') break; //if(doc._ == 'documentEmpty') break;
this.log('will wrap pending video:', pending, message, doc); 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'); if(withTail) bubble.classList.add('with-media-tail');
wrapVideo({ wrapVideo({
doc, doc,
@ -1789,7 +1826,7 @@ export default class ChatBubbles {
break; break;
} }
const withTail = !isAndroid && !message.message; const withTail = !isAndroid && !message.message && !withReplyFooter;
if(withTail) bubble.classList.add('with-media-tail'); if(withTail) bubble.classList.add('with-media-tail');
wrapPhoto({ wrapPhoto({
photo, photo,
@ -1917,7 +1954,7 @@ export default class ChatBubbles {
box.append(quote); box.append(quote);
//bubble.prepend(box); //bubble.prepend(box);
bubbleContainer.prepend(timeSpan, box); messageDiv.insertBefore(box, messageDiv.lastElementChild);
//this.log('night running', bubble.scrollHeight); //this.log('night running', bubble.scrollHeight);
@ -1973,7 +2010,7 @@ export default class ChatBubbles {
chat: this.chat chat: this.chat
}); });
} else { } 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'); if(withTail) bubble.classList.add('with-media-tail');
wrapVideo({ wrapVideo({
doc, doc,
@ -2123,7 +2160,7 @@ export default class ChatBubbles {
nameContainer.append(nameDiv); nameContainer.append(nameDiv);
} }
} else { } 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 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) || ''; let originalPeerTitle = this.appPeersManager.getPeerTitle(originalMessage.fromId || originalMessage.fwdFromId, true) || '';
@ -2186,7 +2223,7 @@ export default class ChatBubbles {
if(savedFrom) { if(savedFrom) {
const goto = document.createElement('div'); 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); bubbleContainer.append(goto);
bubble.dataset.savedFrom = savedFrom; bubble.dataset.savedFrom = savedFrom;
bubble.classList.add('with-beside-button'); bubble.classList.add('with-beside-button');
@ -2201,6 +2238,15 @@ export default class ChatBubbles {
this.bubbleGroups.updateGroupByMessageId(message.mid); this.bubbleGroups.updateGroupByMessageId(message.mid);
} }
if(withReplyFooter) {
MessageRender.renderReplies({
bubble,
bubbleContainer,
message,
messageDiv
});
}
return bubble; return bubble;
} }
@ -2229,14 +2275,9 @@ export default class ChatBubbles {
} }
} */ } */
let dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0]; const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);
if(dialog && dialog.top_message) { if(history.includes(historyStorage.maxId)) {
for(let mid of history) { this.scrolledAllDown = true;
if(mid == dialog.top_message) {
this.scrolledAllDown = true;
break;
}
}
} }
//console.time('appImManager render history'); //console.time('appImManager render history');
@ -2332,21 +2373,12 @@ export default class ChatBubbles {
public requestHistory(maxId: number, loadCount: number, backLimit: number) { public requestHistory(maxId: number, loadCount: number, backLimit: number) {
//const middleware = this.getMiddleware(); //const middleware = this.getMiddleware();
if(this.chat.type === 'chat') { if(this.chat.type === 'chat' || this.chat.type === 'discussion') {
return this.appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit); return this.appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit, this.chat.threadId);
} else if(this.chat.type === 'pinned') { } else if(this.chat.type === 'pinned') {
const promise = this.appMessagesManager.getSearch(this.peerId, '', {_: 'inputMessagesFilterPinned'}, maxId, loadCount, 0, backLimit) const promise = this.appMessagesManager.getSearch(this.peerId, '', {_: 'inputMessagesFilterPinned'}, maxId, loadCount, 0, backLimit)
.then(value => ({history: value.history.map(m => m.mid)})); .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; return promise;
} else if(this.chat.type === 'scheduled') { } else if(this.chat.type === 'scheduled') {
return this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => { return this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => {
@ -2403,7 +2435,7 @@ export default class ChatBubbles {
let additionMsgIds: number[]; let additionMsgIds: number[];
if(additionMsgId && !isBackLimit) { if(additionMsgId && !isBackLimit) {
const historyStorage = this.appMessagesManager.getHistoryStorage(peerId); const historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);
if(historyStorage.history.length < loadCount) { if(historyStorage.history.length < loadCount) {
additionMsgIds = historyStorage.history.slice(); additionMsgIds = historyStorage.history.slice();
@ -2554,8 +2586,8 @@ export default class ChatBubbles {
// preload more // preload more
//if(!isFirstMessageRender) { //if(!isFirstMessageRender) {
if(this.chat.type === 'chat') { if(this.chat.type === 'chat' || this.chat.type === 'discussion') {
const storage = this.appMessagesManager.getHistoryStorage(peerId); const storage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);
const isMaxIdInHistory = storage.history.indexOf(maxId) !== -1; const isMaxIdInHistory = storage.history.indexOf(maxId) !== -1;
if(isMaxIdInHistory) { // * otherwise it is a search or jump if(isMaxIdInHistory) { // * otherwise it is a search or jump
setTimeout(() => { setTimeout(() => {
@ -2578,10 +2610,11 @@ export default class ChatBubbles {
return; return;
} }
let dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0]; const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);
if(!dialog?.unread_count) return; 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); 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]) { if(maxId && this.bubbles[maxId]) {
@ -2591,7 +2624,7 @@ export default class ChatBubbles {
this.firstUnreadBubble = null; this.firstUnreadBubble = null;
} }
if(maxId != dialog.top_message) { if(maxId !== historyStorage.maxId) {
bubble.classList.add('is-first-unread'); bubble.classList.add('is-first-unread');
} }

19
src/components/chat/chat.ts

@ -36,6 +36,7 @@ export default class Chat extends EventListenerBase<{
public contextMenu: ChatContextMenu; public contextMenu: ChatContextMenu;
public peerId = 0; public peerId = 0;
public threadId: number;
public setPeerPromise: Promise<void>; public setPeerPromise: Promise<void>;
public peerChanged: boolean; public peerChanged: boolean;
@ -55,7 +56,7 @@ export default class Chat extends EventListenerBase<{
// * constructor end // * constructor end
this.log = logger('CHAT', LogLevels.log | LogLevels.warn | LogLevels.debug | LogLevels.error); 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.container.append(this.backgroundEl);
this.appImManager.chatsContainer.append(this.container); this.appImManager.chatsContainer.append(this.container);
@ -95,6 +96,9 @@ export default class Chat extends EventListenerBase<{
} else if(this.type === 'scheduled') { } else if(this.type === 'scheduled') {
this.bubbles.constructScheduledHelpers(); this.bubbles.constructScheduledHelpers();
this.input.constructPeerHelpers(); this.input.constructPeerHelpers();
} else if(this.type === 'discussion') {
this.bubbles.constructPeerHelpers();
this.input.constructPeerHelpers();
} }
this.container.classList.add('type-' + this.type); this.container.classList.add('type-' + this.type);
@ -102,7 +106,7 @@ export default class Chat extends EventListenerBase<{
} }
public destroy() { public destroy() {
const perf = performance.now(); //const perf = performance.now();
this.topbar.destroy(); this.topbar.destroy();
this.bubbles.destroy(); this.bubbles.destroy();
@ -116,7 +120,7 @@ export default class Chat extends EventListenerBase<{
this.container.remove(); this.container.remove();
this.log.error('Chat destroy time:', performance.now() - perf); //this.log.error('Chat destroy time:', performance.now() - perf);
} }
public cleanup() { public cleanup() {
@ -132,6 +136,11 @@ export default class Chat extends EventListenerBase<{
this.init = null; this.init = null;
} }
if(this.type === 'discussion' && !this.threadId) {
this.threadId = lastMsgId;
lastMsgId = 0;
}
//console.time('appImManager setPeer'); //console.time('appImManager setPeer');
//console.time('appImManager setPeer pre promise'); //console.time('appImManager setPeer pre promise');
////console.time('appImManager: pre render start'); ////console.time('appImManager: pre render start');
@ -178,9 +187,9 @@ export default class Chat extends EventListenerBase<{
appSidebarRight.sharedMediaTab.setLoadMutex(this.setPeerPromise); appSidebarRight.sharedMediaTab.setLoadMutex(this.setPeerPromise);
appSidebarRight.sharedMediaTab.loadSidebarMedia(true); appSidebarRight.sharedMediaTab.loadSidebarMedia(true);
this.setPeerPromise.then(() => { /* this.setPeerPromise.then(() => {
appSidebarRight.sharedMediaTab.loadSidebarMedia(false); appSidebarRight.sharedMediaTab.loadSidebarMedia(false);
}); }); */
return this.setPeerPromise; return this.setPeerPromise;
} }

11
src/components/chat/input.ts

@ -89,7 +89,7 @@ export default class ChatInput {
private scrollOffsetTop = 0; private scrollOffsetTop = 0;
private scrollDiff = 0; private scrollDiff = 0;
private helperType: Exclude<ChatInputHelperType, 'webpage'>; public helperType: Exclude<ChatInputHelperType, 'webpage'>;
private helperFunc: () => void; private helperFunc: () => void;
private helperWaitingForward: boolean; private helperWaitingForward: boolean;
@ -382,7 +382,8 @@ export default class ChatInput {
duration, duration,
waveform: result.waveform, waveform: result.waveform,
objectURL: result.url, objectURL: result.url,
replyToMsgId: this.replyToMsgId replyToMsgId: this.replyToMsgId,
threadId: this.chat.threadId
}); });
this.onMessageSent(false, true); this.onMessageSent(false, true);
@ -455,7 +456,7 @@ export default class ChatInput {
} }
public destroy() { public destroy() {
this.chat.log.error('Input destroying'); //this.chat.log.error('Input destroying');
emoticonsDropdown.events.onOpen.findAndSplice(f => f == this.onEmoticonsOpen); emoticonsDropdown.events.onOpen.findAndSplice(f => f == this.onEmoticonsOpen);
emoticonsDropdown.events.onClose.findAndSplice(f => f == this.onEmoticonsClose); emoticonsDropdown.events.onClose.findAndSplice(f => f == this.onEmoticonsClose);
@ -1108,6 +1109,7 @@ export default class ChatInput {
} else { } else {
this.appMessagesManager.sendText(this.chat.peerId, str, { this.appMessagesManager.sendText(this.chat.peerId, str, {
replyToMsgId: this.replyToMsgId, replyToMsgId: this.replyToMsgId,
threadId: this.chat.threadId,
noWebPage: this.noWebPage, noWebPage: this.noWebPage,
webPage: this.willSendWebPage, webPage: this.willSendWebPage,
scheduleDate: this.scheduleDate, scheduleDate: this.scheduleDate,
@ -1151,6 +1153,7 @@ export default class ChatInput {
this.appMessagesManager.sendFile(this.chat.peerId, document, { this.appMessagesManager.sendFile(this.chat.peerId, document, {
isMedia: true, isMedia: true,
replyToMsgId: this.replyToMsgId, replyToMsgId: this.replyToMsgId,
threadId: this.chat.threadId,
silent: this.sendSilent, silent: this.sendSilent,
scheduleDate: this.scheduleDate scheduleDate: this.scheduleDate
}); });
@ -1235,7 +1238,7 @@ export default class ChatInput {
this.willSendWebPage = null; this.willSendWebPage = null;
} }
this.replyToMsgId = undefined; this.replyToMsgId = this.chat.threadId;
this.forwardingMids.length = 0; this.forwardingMids.length = 0;
this.forwardingFromPeerId = 0; this.forwardingFromPeerId = 0;
this.editMsgId = undefined; this.editMsgId = undefined;

55
src/components/chat/messageRender.ts

@ -1,6 +1,9 @@
import { getFullDate } from "../../helpers/date"; import { getFullDate } from "../../helpers/date";
import { formatNumber } from "../../helpers/number"; import { formatNumber } from "../../helpers/number";
import { MessageReplies } from "../../layer";
import appPeersManager from "../../lib/appManagers/appPeersManager";
import RichTextProcessor from "../../lib/richtextprocessor"; import RichTextProcessor from "../../lib/richtextprocessor";
import { ripple } from "../ripple";
import Chat from "./chat"; import Chat from "./chat";
type Message = any; type Message = any;
@ -58,4 +61,56 @@ export namespace MessageRender {
return timeSpan; 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);
}
};
} }

4
src/components/chat/selection.ts

@ -304,9 +304,7 @@ export default class ChatSelection {
this.cancelSelection(); this.cancelSelection();
}) })
}); });
} } else {
if(this.chat.type === 'chat' || this.chat.type === 'pinned') {
this.selectionForwardBtn = Button('btn-primary btn-transparent selection-container-forward', {icon: 'forward'}); this.selectionForwardBtn = Button('btn-primary btn-transparent selection-container-forward', {icon: 'forward'});
this.selectionForwardBtn.append('Forward'); this.selectionForwardBtn.append('Forward');
this.listenerSetter.add(this.selectionForwardBtn, 'click', () => { this.listenerSetter.add(this.selectionForwardBtn, 'click', () => {

18
src/components/chat/topbar.ts

@ -50,7 +50,7 @@ export default class ChatTopbar {
} }
public construct() { public construct() {
this.chat.log.error('Topbar construction'); //this.chat.log.error('Topbar construction');
this.container = document.createElement('div'); this.container = document.createElement('div');
this.container.classList.add('sidebar-header', 'topbar'); this.container.classList.add('sidebar-header', 'topbar');
@ -320,7 +320,7 @@ export default class ChatTopbar {
}; };
public destroy() { public destroy() {
this.chat.log.error('Topbar destroying'); //this.chat.log.error('Topbar destroying');
this.listenerSetter.removeAll(); this.listenerSetter.removeAll();
mediaSizes.removeListener('changeScreen', this.onChangeScreen); mediaSizes.removeListener('changeScreen', this.onChangeScreen);
@ -386,7 +386,6 @@ export default class ChatTopbar {
public setTitle(count?: number) { public setTitle(count?: number) {
let title = ''; let title = '';
if(this.chat.type === 'pinned') { 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(' '); title = [count > 1 ? count : false, 'Pinned Messages'].filter(Boolean).join(' ');
if(count === undefined) { if(count === undefined) {
@ -408,10 +407,8 @@ export default class ChatTopbar {
} }
} else if(this.chat.type === 'scheduled') { } else if(this.chat.type === 'scheduled') {
if(this.peerId === rootScope.myId) { if(this.peerId === rootScope.myId) {
//title = !count ? 'Reminders' : (count === 1 ? 'Reminder' : (count + ' Reminders'));
title = [count > 1 ? count : false, 'Reminders'].filter(Boolean).join(' '); title = [count > 1 ? count : false, 'Reminders'].filter(Boolean).join(' ');
} else { } else {
//title = !count ? 'Scheduled Messages' : (count === 1 ? 'Scheduled Message' : (count + ' Scheduled Messages'));
title = [count > 1 ? count : false, 'Scheduled Messages'].filter(Boolean).join(' '); title = [count > 1 ? count : false, 'Scheduled Messages'].filter(Boolean).join(' ');
} }
@ -420,6 +417,17 @@ export default class ChatTopbar {
this.setTitle(mids.length); 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') { } else if(this.chat.type === 'chat') {
if(this.peerId == rootScope.myId) title = 'Saved Messages'; if(this.peerId == rootScope.myId) title = 'Saved Messages';
else title = this.appPeersManager.getPeerTitle(this.peerId); else title = this.appPeersManager.getPeerTitle(this.peerId);

2
src/components/poll.ts

@ -531,7 +531,7 @@ export default class PollElement extends HTMLElement {
*/ */
results.recent_voters/* .slice().reverse() */.forEach((userId, idx) => { results.recent_voters/* .slice().reverse() */.forEach((userId, idx) => {
const style = idx == 0 ? '' : `style="transform: translateX(-${idx * 3}px);"`; 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; this.avatarsDiv.innerHTML = html;
} }

6
src/components/popups/createPoll.ts

@ -241,10 +241,16 @@ export default class PopupCreatePoll extends PopupElement {
//console.log('Will try to create poll:', inputMediaPoll); //console.log('Will try to create poll:', inputMediaPoll);
this.chat.appMessagesManager.sendOther(this.chat.peerId, inputMediaPoll, { this.chat.appMessagesManager.sendOther(this.chat.peerId, inputMediaPoll, {
threadId: this.chat.threadId,
replyToMsgId: this.chat.input.replyToMsgId,
scheduleDate: this.chat.input.scheduleDate, scheduleDate: this.chat.input.scheduleDate,
silent: this.chat.input.sendSilent silent: this.chat.input.sendSilent
}); });
if(this.chat.input.helperType === 'reply') {
this.chat.input.clearHelper();
}
this.chat.input.onMessageSent(false, false); this.chat.input.onMessageSent(false, false);
} }

52
src/components/popups/datePicker.ts

@ -28,7 +28,8 @@ export default class PopupDatePicker extends PopupElement {
noTitle: true, noTitle: true,
minDate: Date, minDate: Date,
maxDate: Date maxDate: Date
withTime: true withTime: true,
showOverflowMonths: true
}> & PopupOptions = {}) { }> & PopupOptions = {}) {
super('popup-date-picker', options.noButtons ? [] : [{ super('popup-date-picker', options.noButtons ? [] : [{
text: 'CANCEL', 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]; 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() { public setMonth() {
this.monthTitle.innerText = months[this.selectedMonth.getMonth()] + ' ' + this.selectedMonth.getFullYear(); 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']; const days = ['M', 'T', 'W', 'T', 'F', 'S', 'S'];
this.month.append(...days.map(s => { this.month.append(...days.map(s => {
const el = document.createElement('span'); const el = this.renderElement(true, s);
el.innerText = s; el.classList.remove('date-picker-month-date');
el.classList.add('date-picker-month-day');
return el; return el;
})); }));
@ -274,23 +291,24 @@ export default class PopupDatePicker extends PopupElement {
let dayIndex = firstDate.getDay() - 1; let dayIndex = firstDate.getDay() - 1;
if(dayIndex == -1) dayIndex = days.length - 1; if(dayIndex == -1) dayIndex = days.length - 1;
const clonedDate = new Date(firstDate.getTime());
clonedDate.setDate(clonedDate.getDate() - dayIndex - 1);
// Padding first week // Padding first week
for(let i = 0; i < dayIndex; ++i) { for(let i = 0; i < dayIndex; ++i) {
const el = document.createElement('span'); if(this.options.showOverflowMonths) {
this.month.append(el); clonedDate.setDate(clonedDate.getDate() + 1);
this.month.append(this.renderElement(true, '' + clonedDate.getDate()));
} else {
this.month.append(this.renderElement(true));
}
} }
do { do {
const date = firstDate.getDate(); const date = firstDate.getDate();
const el = document.createElement('button'); const el = this.renderElement(firstDate > this.maxDate || firstDate < this.minDate, '' + date);
el.classList.add('btn-icon');
el.innerText = '' + date;
el.dataset.timestamp = '' + firstDate.getTime(); el.dataset.timestamp = '' + firstDate.getTime();
if(firstDate > this.maxDate || firstDate < this.minDate) {
el.setAttribute('disabled', 'true');
}
if(firstDate.getTime() === this.selectedDate.getTime()) { if(firstDate.getTime() === this.selectedDate.getTime()) {
this.selectedEl = el; this.selectedEl = el;
el.classList.add('active'); el.classList.add('active');
@ -301,6 +319,14 @@ export default class PopupDatePicker extends PopupElement {
firstDate.setDate(date + 1); firstDate.setDate(date + 1);
} while(firstDate.getDate() !== 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.container.classList.toggle('is-max-lines', (this.month.childElementCount / 7) > 6);
this.monthsContainer.append(this.month); this.monthsContainer.append(this.month);

6
src/components/popups/deleteMessages.ts

@ -11,7 +11,7 @@ export default class PopupDeleteMessages {
const firstName = appPeersManager.getPeerTitle(peerId, false, true); const firstName = appPeersManager.getPeerTitle(peerId, false, true);
mids = mids.slice(); mids = mids.slice();
const callback = (revoke: boolean) => { const callback = (revoke?: true) => {
onConfirm && onConfirm(); onConfirm && onConfirm();
if(type === 'scheduled') { if(type === 'scheduled') {
appMessagesManager.deleteScheduledMessages(peerId, mids); appMessagesManager.deleteScheduledMessages(peerId, mids);
@ -28,13 +28,13 @@ export default class PopupDeleteMessages {
buttons = [{ buttons = [{
text: 'DELETE', text: 'DELETE',
isDanger: true, isDanger: true,
callback: () => callback(false) callback: () => callback()
}]; }];
} else { } else {
buttons = [{ buttons = [{
text: 'DELETE JUST FOR ME', text: 'DELETE JUST FOR ME',
isDanger: true, isDanger: true,
callback: () => callback(false) callback: () => callback()
}]; }];
if(peerId > 0) { if(peerId > 0) {

16
src/components/popups/newMedia.ts

@ -162,20 +162,26 @@ export default class PopupNewMedia extends PopupElement {
this.chat.appMessagesManager.sendAlbum(peerId, w.sendFileDetails.map(d => d.file), Object.assign({ this.chat.appMessagesManager.sendAlbum(peerId, w.sendFileDetails.map(d => d.file), Object.assign({
caption, caption,
replyToMsgId: input.replyToMsgId, replyToMsgId: input.replyToMsgId,
threadId: this.chat.threadId,
isMedia: willAttach.isMedia, isMedia: willAttach.isMedia,
silent, silent,
scheduleDate scheduleDate
}, w)); }, w));
caption = undefined; caption = undefined;
input.replyToMsgId = undefined; input.replyToMsgId = this.chat.threadId;
} }
} else { } else {
if(caption) { if(caption) {
if(willAttach.sendFileDetails.length > 1) { 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 = ''; caption = '';
input.replyToMsgId = undefined; //input.replyToMsgId = undefined;
} }
} }
@ -185,14 +191,16 @@ export default class PopupNewMedia extends PopupElement {
isMedia: willAttach.isMedia, isMedia: willAttach.isMedia,
caption, caption,
replyToMsgId: input.replyToMsgId, replyToMsgId: input.replyToMsgId,
threadId: this.chat.threadId,
silent, silent,
scheduleDate scheduleDate
}, params)); }, params));
caption = ''; caption = '';
input.replyToMsgId = undefined;
return promise; return promise;
}); });
input.replyToMsgId = this.chat.threadId;
} }
//Promise.all(promises); //Promise.all(promises);

3
src/components/popups/schedule.ts

@ -21,7 +21,8 @@ export default class PopupSchedule extends PopupDatePicker {
date.setDate(date.getDate() - 1); date.setDate(date.getDate() - 1);
return date; return date;
})(), })(),
withTime: true withTime: true,
showOverflowMonths: true
}); });
this.element.classList.add('popup-schedule'); this.element.classList.add('popup-schedule');

4
src/components/sidebarLeft/tabs/addMembers.ts

@ -29,7 +29,7 @@ export default class AppAddMembersTab implements SliderTab {
return; return;
} }
this.nextBtn.classList.remove('tgico-next'); this.nextBtn.classList.remove('tgico-arrow-next');
this.nextBtn.disabled = true; this.nextBtn.disabled = true;
putPreloader(this.nextBtn); putPreloader(this.nextBtn);
this.selector.freezed = true; this.selector.freezed = true;
@ -61,7 +61,7 @@ export default class AppAddMembersTab implements SliderTab {
this.nextBtn.innerHTML = ''; this.nextBtn.innerHTML = '';
this.nextBtn.disabled = false; this.nextBtn.disabled = false;
this.nextBtn.classList.add('tgico-next'); this.nextBtn.classList.add('tgico-arrow-next');
this.nextBtn.classList.toggle('is-visible', skippable); this.nextBtn.classList.toggle('is-visible', skippable);
appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.addMembers); appSidebarLeft.selectTab(AppSidebarLeft.SLIDERITEMSIDS.addMembers);

2
src/components/wrappers.ts

@ -351,7 +351,7 @@ export function wrapDocument({message, withTime, uploading, fontWeight}: {
}): HTMLElement { }): HTMLElement {
if(!fontWeight) fontWeight = 500; 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') { if(doc.type == 'audio' || doc.type == 'voice') {
const audioElement = new AudioElement(); const audioElement = new AudioElement();
audioElement.setAttribute('message-id', '' + message.mid); audioElement.setAttribute('message-id', '' + message.mid);

4
src/lib/appManagers/appImManager.ts

@ -455,9 +455,9 @@ export class AppImManager {
appSidebarRight.sharedMediaTab.loadSidebarMedia(true); appSidebarRight.sharedMediaTab.loadSidebarMedia(true);
appSidebarRight.sharedMediaTab.fillProfileElements(); appSidebarRight.sharedMediaTab.fillProfileElements();
setTimeout(() => { /* setTimeout(() => {
appSidebarRight.sharedMediaTab.loadSidebarMedia(false); appSidebarRight.sharedMediaTab.loadSidebarMedia(false);
}); }); */
} }
setTimeout(() => { setTimeout(() => {

345
src/lib/appManagers/appMessagesManager.ts

@ -4,7 +4,7 @@ import { tsNow } from "../../helpers/date";
import { copy, defineNotNumerableProperties, getObjectKeysAndSort } from "../../helpers/object"; import { copy, defineNotNumerableProperties, getObjectKeysAndSort } from "../../helpers/object";
import { randomLong } from "../../helpers/random"; import { randomLong } from "../../helpers/random";
import { splitStringByLength, limitSymbols } from "../../helpers/string"; 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 { InvokeApiOptions } from "../../types";
import { langPack } from "../langPack"; import { langPack } from "../langPack";
import { logger, LogLevels } from "../logger"; import { logger, LogLevels } from "../logger";
@ -43,8 +43,11 @@ export type HistoryStorage = {
history: number[], history: number[],
pending: number[], pending: number[],
maxId?: number,
readPromise?: Promise<boolean>, readPromise?: Promise<boolean>,
readMaxId?: number, readMaxId?: number,
readOutboxMaxId?: number,
maxOutId?: number, maxOutId?: number,
reply_markup?: any reply_markup?: any
}; };
@ -89,6 +92,11 @@ export class AppMessagesManager {
public historiesStorage: { public historiesStorage: {
[peerId: string]: HistoryStorage [peerId: string]: HistoryStorage
} = {}; } = {};
public threadsStorage: {
[peerId: string]: {
[threadId: string]: HistoryStorage
}
} = {};
public searchesStorage: { public searchesStorage: {
[peerId: string]: Partial<{ [peerId: string]: Partial<{
[inputFilter in MyInputMessagesFilter]: { [inputFilter in MyInputMessagesFilter]: {
@ -386,6 +394,7 @@ export class AppMessagesManager {
public sendText(peerId: number, text: string, options: Partial<{ public sendText(peerId: number, text: string, options: Partial<{
entities: any[], entities: any[],
replyToMsgId: number, replyToMsgId: number,
threadId: number,
viaBotId: number, viaBotId: number,
queryId: string, queryId: string,
resultId: string, resultId: string,
@ -462,7 +471,7 @@ export class AppMessagesManager {
date: options.scheduleDate || (tsNow(true) + serverTimeManager.serverTimeOffset), date: options.scheduleDate || (tsNow(true) + serverTimeManager.serverTimeOffset),
message: text, message: text,
random_id: randomIdS, random_id: randomIdS,
reply_to: {reply_to_msg_id: replyToMsgId}, reply_to: this.generateReplyHeader(options.replyToMsgId, options.threadId),
via_bot_id: options.viaBotId, via_bot_id: options.viaBotId,
reply_markup: options.reply_markup, reply_markup: options.reply_markup,
entities: entities, entities: entities,
@ -579,6 +588,7 @@ export class AppMessagesManager {
isMedia: true, isMedia: true,
replyToMsgId: number, replyToMsgId: number,
threadId: number,
caption: string, caption: string,
entities: MessageEntity[], entities: MessageEntity[],
width: number, width: number,
@ -785,7 +795,7 @@ export class AppMessagesManager {
document: file document: file
} : media, } : media,
random_id: randomIdS, random_id: randomIdS,
reply_to: {reply_to_msg_id: replyToMsgId}, reply_to: this.generateReplyHeader(options.replyToMsgId, options.threadId),
views: asChannel && 1, views: asChannel && 1,
pending: true pending: true
}; };
@ -923,6 +933,7 @@ export class AppMessagesManager {
isMedia: true, isMedia: true,
entities: MessageEntity[], entities: MessageEntity[],
replyToMsgId: number, replyToMsgId: number,
threadId: number,
caption: string, caption: string,
sendFileDetails: Partial<{ sendFileDetails: Partial<{
duration: number, duration: number,
@ -958,13 +969,15 @@ export class AppMessagesManager {
isMedia: options.isMedia, isMedia: options.isMedia,
scheduleDate: options.scheduleDate, scheduleDate: options.scheduleDate,
silent: options.silent, silent: options.silent,
replyToMsgId,
threadId: options.threadId,
...details ...details
}; };
if(idx === 0) { if(idx === 0) {
o.caption = caption; o.caption = caption;
o.entities = entities; o.entities = entities;
o.replyToMsgId = replyToMsgId; //o.replyToMsgId = replyToMsgId;
} }
return this.sendFile(peerId, file, o).message; return this.sendFile(peerId, file, o).message;
@ -1058,6 +1071,7 @@ export class AppMessagesManager {
public sendOther(peerId: number, inputMedia: any, options: Partial<{ public sendOther(peerId: number, inputMedia: any, options: Partial<{
replyToMsgId: number, replyToMsgId: number,
threadId: number,
viaBotId: number, viaBotId: number,
reply_markup: any, reply_markup: any,
clearDraft: true, clearDraft: true,
@ -1181,7 +1195,7 @@ export class AppMessagesManager {
message: '', message: '',
media, media,
random_id: randomIdS, random_id: randomIdS,
reply_to: {reply_to_msg_id: replyToMsgId}, reply_to: this.generateReplyHeader(options.replyToMsgId, options.threadId),
via_bot_id: options.viaBotId, via_bot_id: options.viaBotId,
reply_markup: options.reply_markup, reply_markup: options.reply_markup,
views: asChannel && 1, 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) { private setDialogIndexByMessage(dialog: MTDialog.dialog, message: MyMessage) {
if(!dialog.pFlags.pinned || !dialog.index) { if(!dialog.pFlags.pinned || !dialog.index) {
dialog.index = this.dialogsStorage.generateDialogIndex(message.date); dialog.index = this.dialogsStorage.generateDialogIndex(message.date);
@ -1309,6 +1336,9 @@ export class AppMessagesManager {
const dialog = this.getDialogByPeerId(message.peerId)[0]; const dialog = this.getDialogByPeerId(message.peerId)[0];
if(dialog) { if(dialog) {
dialog.top_message = message.mid; dialog.top_message = message.mid;
const historyStorage = this.getHistoryStorage(message.peerId);
historyStorage.maxId = message.mid;
this.setDialogIndexByMessage(dialog, message); 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> { public getTopMessages(limit: number, folderId: number): Promise<number> {
const dialogs = this.dialogsStorage.getFolder(folderId); const dialogs = this.dialogsStorage.getFolder(folderId);
let offsetId = 0; let offsetId = 0;
@ -1492,7 +1527,7 @@ export class AppMessagesManager {
(dialogsResult.dialogs as Dialog[]).forEachReverse(dialog => { (dialogsResult.dialogs as Dialog[]).forEachReverse(dialog => {
//const d = Object.assign({}, dialog); //const d = Object.assign({}, dialog);
// ! нужно передавать folderId, так как по папке != 0 нет свойства folder_id // ! нужно передавать folderId, так как по папке != 0 нет свойства folder_id
this.saveConversation(dialog, folderId); this.saveConversation(dialog, dialog.folder_id ?? folderId);
/* if(dialog.peerId == -1213511294) { /* if(dialog.peerId == -1213511294) {
this.log.error('lun bot', folderId, d); this.log.error('lun bot', folderId, d);
@ -1505,9 +1540,11 @@ export class AppMessagesManager {
// ! это может случиться, если запрос идёт не по папке 0, а по 1. почему-то read'ов нет // ! это может случиться, если запрос идёт не по папке 0, а по 1. почему-то read'ов нет
// ! в итоге, чтобы получить 1 диалог, делается первый запрос по папке 0, потом запрос для архивных по папке 1, и потом ещё перезагрузка архивного диалога // ! в итоге, чтобы получить 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; noIdsDialogs[dialog.peerId] = dialog;
this.log.error('noIdsDialogs', dialog);
/* if(dialog.peerId == -1213511294) { /* if(dialog.peerId == -1213511294) {
this.log.error('lun bot', folderId); this.log.error('lun bot', folderId);
} */ } */
@ -1622,7 +1659,7 @@ export class AppMessagesManager {
public getMessageById(messageId: number) { public getMessageById(messageId: number) {
for(const peerId in this.messagesStorageByPeerId) { for(const peerId in this.messagesStorageByPeerId) {
if(appPeersManager.isChannel(-+peerId)) { if(appPeersManager.isChannel(+peerId)) {
continue; continue;
} }
@ -1849,7 +1886,7 @@ export class AppMessagesManager {
public generateMessageId(messageId: number, temp = false) { public generateMessageId(messageId: number, temp = false) {
const q = 0xFFFFFFFF; const q = 0xFFFFFFFF;
const num = temp ? ++this.tempNum : 0; const num = temp ? ++this.tempNum : 0;
if(messageId > q) { if(messageId >= q) {
if(temp) { if(temp) {
return messageId + (num & 0xFFFF); return messageId + (num & 0xFFFF);
} }
@ -1865,7 +1902,7 @@ export class AppMessagesManager {
*/ */
public getLocalMessageId(messageId: number) { public getLocalMessageId(messageId: number) {
const q = 0xFFFFFFFF; const q = 0xFFFFFFFF;
if(messageId < q) { if(messageId <= q) {
return messageId; 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']) // 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) { if(message.reply_to) {
//message.reply_to_mid = message.reply_to.reply_to_msg_id; if(message.reply_to.reply_to_msg_id) {
message.reply_to_mid = this.generateMessageId(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; const overwriting = !!message.peerId;
@ -1945,7 +1990,8 @@ export class AppMessagesManager {
if(message.peerId == myId/* && !message.from_id && !message.fwd_from */) { 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; message.fromId = message.fwd_from ? (message.fwd_from.from_id ? appPeersManager.getPeerId(message.fwd_from.from_id) : 0) : myId;
} else { } 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; const fwdHeader = message.fwd_from;
@ -2449,6 +2495,7 @@ export class AppMessagesManager {
if(!topMessage if(!topMessage
|| (this.getMessageByPeer(peerId, topPendingMessage) as MyMessage).date > (this.getMessageByPeer(peerId, topMessage) as MyMessage).date) { || (this.getMessageByPeer(peerId, topPendingMessage) as MyMessage).date > (this.getMessageByPeer(peerId, topMessage) as MyMessage).date) {
dialog.top_message = topMessage = topPendingMessage; 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.top_message = mid;
dialog.read_inbox_max_id = this.generateMessageId(dialog.read_inbox_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 = this.generateMessageId(dialog.read_outbox_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.hasOwnProperty('folder_id')) {
if(dialog._ == 'dialog') { if(dialog._ == 'dialog') {
// ! СЛОЖНО ! СМОТРИ В getTopMessages // ! СЛОЖНО ! СМОТРИ В getTopMessages
const wasDialogBefore = this.getDialogByPeerId(peerId)[0];
dialog.folder_id = wasDialogBefore ? wasDialogBefore.folder_id : folderId; dialog.folder_id = wasDialogBefore ? wasDialogBefore.folder_id : folderId;
}/* else if(dialog._ == 'dialogFolder') { }/* else if(dialog._ == 'dialogFolder') {
dialog.folder_id = dialog.folder.id; dialog.folder_id = dialog.folder.id;
@ -2562,12 +2610,9 @@ export class AppMessagesManager {
dialog.peerId = peerId; dialog.peerId = peerId;
this.dialogsStorage.generateIndexForDialog(dialog);
this.dialogsStorage.pushDialog(dialog, message.date);
// Because we saved message without dialog present // Because we saved message without dialog present
if(message.mid > 0) { if(mid > 0) {
if(message.mid > dialog[message.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id']) message.pFlags.unread = true; if(mid > dialog[message.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id']) message.pFlags.unread = true;
else delete message.pFlags.unread; else delete message.pFlags.unread;
} }
@ -2584,13 +2629,16 @@ export class AppMessagesManager {
historyStorage[mid > 0 ? 'history' : 'pending'].push(mid); 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) { if(channelId && dialog.pts) {
apiUpdatesManager.addChannelState(channelId, dialog.pts); apiUpdatesManager.addChannelState(channelId, dialog.pts);
} }
//if(this.filtersStorage.inited) { this.dialogsStorage.generateIndexForDialog(dialog);
//this.filtersStorage.processDialog(dialog); this.dialogsStorage.pushDialog(dialog, message.date);
//}
} }
public mergeReplyKeyboard(historyStorage: HistoryStorage, message: any) { 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: { public getSearch(peerId = 0, query: string = '', inputFilter: {
_: MyInputMessagesFilter _: 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, count: number,
next_rate: number, next_rate: number,
offset_id_offset: number, offset_id_offset: number,
@ -2704,7 +2767,7 @@ export class AppMessagesManager {
}; };
// * костыль для limit 1, если нужно и получить сообщение, и узнать количество сообщений // * костыль для limit 1, если нужно и получить сообщение, и узнать количество сообщений
if(peerId && !backLimit && !maxId && !query && limit !== 1/* && inputFilter._ !== 'inputMessagesFilterPinned' */) { if(peerId && !backLimit && !maxId && !query && limit !== 1 && !threadId/* && inputFilter._ !== 'inputMessagesFilterPinned' */) {
storage = beta ? storage = beta ?
this.getSearchStorage(peerId, inputFilter._) : this.getSearchStorage(peerId, inputFilter._) :
this.getHistoryStorage(peerId); this.getHistoryStorage(peerId);
@ -2860,19 +2923,20 @@ export class AppMessagesManager {
add_offset: backLimit ? -backLimit : 0, add_offset: backLimit ? -backLimit : 0,
max_id: 0, max_id: 0,
min_id: 0, min_id: 0,
hash: 0 hash: 0,
top_msg_id: threadId
}, { }, {
//timeout: APITIMEOUT, //timeout: APITIMEOUT,
noErrorBox: true noErrorBox: true
}); });
} else { } else {
var offsetDate = 0; //var offsetDate = 0;
var offsetPeerId = 0; let offsetPeerId = 0;
var offsetId = 0; let offsetId = 0;
var offsetMessage = maxId && this.getMessageByPeer(peerId, maxId); let offsetMessage = maxId && this.getMessageByPeer(peerId, maxId);
if(offsetMessage && offsetMessage.date) { if(offsetMessage && offsetMessage.date) {
offsetDate = offsetMessage.date + serverTimeManager.serverTimeOffset; //offsetDate = offsetMessage.date + serverTimeManager.serverTimeOffset;
offsetId = offsetMessage.id; offsetId = offsetMessage.id;
offsetPeerId = this.getMessagePeer(offsetMessage); offsetPeerId = this.getMessagePeer(offsetMessage);
} }
@ -2885,7 +2949,7 @@ export class AppMessagesManager {
offset_rate: offsetRate, offset_rate: offsetRate,
offset_peer: appPeersManager.getInputPeerById(offsetPeerId), offset_peer: appPeersManager.getInputPeerById(offsetPeerId),
offset_id: offsetId, offset_id: offsetId,
limit limit,
}, { }, {
//timeout: APITIMEOUT, //timeout: APITIMEOUT,
noErrorBox: true 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 = () => { handleNewMessages = () => {
clearTimeout(this.newMessagesHandlePromise); clearTimeout(this.newMessagesHandlePromise);
this.newMessagesHandlePromise = 0; 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>; let promise: Promise<any>;
mids = mids.map(mid => this.getLocalMessageId(mid)); mids = mids.map(mid => this.getLocalMessageId(mid));
if(peerId < 0 && appPeersManager.isChannel(-peerId)) { if(peerId < 0 && appPeersManager.isChannel(peerId)) {
const channelId = -peerId; const channelId = -peerId;
const channel = appChatsManager.getChat(channelId); const channel = appChatsManager.getChat(channelId);
if(!channel.pFlags.creator && !(channel.pFlags.editor && channel.pFlags.megagroup)) { if(!channel.pFlags.creator && !(channel.pFlags.editor && channel.pFlags.megagroup)) {
@ -3015,7 +3098,7 @@ export class AppMessagesManager {
}); });
} else { } else {
promise = apiManager.invokeApi('messages.deleteMessages', { promise = apiManager.invokeApi('messages.deleteMessages', {
revoke: revoke || undefined, revoke,
id: mids id: mids
}).then((affectedMessages) => { }).then((affectedMessages) => {
apiUpdatesManager.processUpdateMessage({ apiUpdatesManager.processUpdateMessage({
@ -3035,24 +3118,10 @@ export class AppMessagesManager {
public readHistory(peerId: number, maxId = 0) { public readHistory(peerId: number, maxId = 0) {
// console.trace('start read') // console.trace('start read')
if(!this.isHistoryUnread(peerId)) return Promise.resolve(true);
const isChannel = appPeersManager.isChannel(peerId); const isChannel = appPeersManager.isChannel(peerId);
const historyStorage = this.getHistoryStorage(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) { if(!historyStorage.readMaxId || maxId > historyStorage.readMaxId) {
historyStorage.readMaxId = maxId; historyStorage.readMaxId = maxId;
@ -3066,7 +3135,7 @@ export class AppMessagesManager {
if(isChannel) { if(isChannel) {
apiPromise = apiManager.invokeApi('channels.readHistory', { apiPromise = apiManager.invokeApi('channels.readHistory', {
channel: appChatsManager.getChannelInput(-peerId), channel: appChatsManager.getChannelInput(-peerId),
max_id: maxId max_id: this.getLocalMessageId(maxId)
}).then((res) => { }).then((res) => {
apiUpdatesManager.processUpdateMessage({ apiUpdatesManager.processUpdateMessage({
_: 'updateShort', _: 'updateShort',
@ -3082,7 +3151,7 @@ export class AppMessagesManager {
} else { } else {
apiPromise = apiManager.invokeApi('messages.readHistory', { apiPromise = apiManager.invokeApi('messages.readHistory', {
peer: appPeersManager.getInputPeerById(peerId), peer: appPeersManager.getInputPeerById(peerId),
max_id: maxId max_id: this.getLocalMessageId(maxId)
}).then((affectedMessages) => { }).then((affectedMessages) => {
apiUpdatesManager.processUpdateMessage({ apiUpdatesManager.processUpdateMessage({
_: 'updateShort', _: 'updateShort',
@ -3111,8 +3180,6 @@ export class AppMessagesManager {
if(historyStorage.readMaxId > maxId) { if(historyStorage.readMaxId > maxId) {
this.readHistory(peerId, historyStorage.readMaxId); 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: []}); return this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {count: null, history: [], pending: []});
} }
@ -3427,7 +3500,6 @@ export class AppMessagesManager {
case 'updateEditChannelMessage': { case 'updateEditChannelMessage': {
const message = update.message as MyMessage; const message = update.message as MyMessage;
const peerId = this.getMessagePeer(message); const peerId = this.getMessagePeer(message);
//const mid = message.id;
const mid = this.generateMessageId(message.id); const mid = this.generateMessageId(message.id);
const storage = this.getMessagesStorage(peerId); const storage = this.getMessagesStorage(peerId);
if(storage[mid] === undefined) { if(storage[mid] === undefined) {
@ -3456,22 +3528,7 @@ export class AppMessagesManager {
mid mid
}); });
const groupId = (message as Message.message).grouped_id; if(isTopMessage || (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) {
const updatedDialogs: {[peerId: number]: Dialog} = {}; const updatedDialogs: {[peerId: number]: Dialog} = {};
updatedDialogs[peerId] = dialog; updatedDialogs[peerId] = dialog;
rootScope.broadcast('dialogs_multiupdate', updatedDialogs); rootScope.broadcast('dialogs_multiupdate', updatedDialogs);
@ -3480,27 +3537,34 @@ export class AppMessagesManager {
break; break;
} }
case 'updateReadChannelDiscussionInbox':
case 'updateReadChannelDiscussionOutbox':
case 'updateReadHistoryInbox': case 'updateReadHistoryInbox':
case 'updateReadHistoryOutbox': case 'updateReadHistoryOutbox':
case 'updateReadChannelInbox': case 'updateReadChannelInbox':
case 'updateReadChannelOutbox': { case 'updateReadChannelOutbox': {
const channelId: number = (update as Update.updateReadChannelInbox).channel_id; const channelId = (update as Update.updateReadChannelInbox).channel_id;
//const maxId = update.max_id; const maxId = this.generateMessageId((update as Update.updateReadChannelInbox).max_id || (update as Update.updateReadChannelDiscussionInbox).read_max_id);
const maxId = this.generateMessageId(update.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 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 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 newUnreadCount = 0;
let foundAffected = false; let foundAffected = false;
//this.log.warn(dT(), 'read', peerId, isOut ? 'out' : 'in', maxId) //this.log.warn(dT(), 'read', peerId, isOut ? 'out' : 'in', maxId)
const historyStorage = this.getHistoryStorage(peerId, threadId);
if(peerId > 0 && isOut) { if(peerId > 0 && isOut) {
appUsersManager.forceUserOnline(peerId); appUsersManager.forceUserOnline(peerId);
} }
const storage = this.getMessagesStorage(peerId);
for(let i = 0, length = history.length; i < length; i++) { for(let i = 0, length = history.length; i < length; i++) {
const messageId = history[i]; const messageId = history[i];
if(messageId > maxId) { if(messageId > maxId) {
@ -3508,9 +3572,6 @@ export class AppMessagesManager {
} }
const message = storage[messageId]; const message = storage[messageId];
if(!message) {
continue;
}
if(message.pFlags.out != isOut) { if(message.pFlags.out != isOut) {
continue; continue;
@ -3519,6 +3580,13 @@ export class AppMessagesManager {
if(!message.pFlags.unread) { if(!message.pFlags.unread) {
break; 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) // this.log.warn('read', messageId, message.pFlags.unread, message)
if(message.pFlags.unread) { if(message.pFlags.unread) {
@ -3527,28 +3595,30 @@ export class AppMessagesManager {
foundAffected = true; foundAffected = true;
} }
if(!message.pFlags.out) { if(!message.pFlags.out && !threadId && stillUnreadCount === undefined) {
if(foundDialog) { newUnreadCount = --foundDialog.unread_count;
newUnreadCount = --foundDialog.unread_count;
}
//NotificationsManager.cancel('msg' + messageId); // warning //NotificationsManager.cancel('msg' + messageId); // warning
} }
} }
} }
if(foundDialog) { if(isOut) historyStorage.readOutboxMaxId = maxId;
if(!isOut && newUnreadCount && foundDialog.top_message <= maxId) { else historyStorage.readMaxId = maxId;
newUnreadCount = foundDialog.unread_count = 0;
}
foundDialog[isOut ? 'read_outbox_max_id' : 'read_inbox_max_id'] = maxId; if(!threadId && foundDialog) {
} if(isOut) foundDialog.read_outbox_max_id = maxId;
else foundDialog.read_inbox_max_id = maxId;
// need be commented for read out messages if(!isOut) {
//if(newUnreadCount != 0 || !isOut) { // fix 16.11.2019 (maybe not) if(newUnreadCount < 0 || !this.isHistoryUnread(peerId)) {
//////////this.log.warn(dT(), 'cnt', peerId, newUnreadCount, isOut, foundDialog, update, foundAffected); foundDialog.unread_count = 0;
rootScope.broadcast('dialog_unread', {peerId, count: newUnreadCount}); } else if(newUnreadCount && foundDialog.top_message > maxId) {
//} foundDialog.unread_count = newUnreadCount;
}
}
rootScope.broadcast('dialog_unread', {peerId});
}
if(foundAffected) { if(foundAffected) {
rootScope.broadcast('messages_read'); rootScope.broadcast('messages_read');
@ -3625,10 +3695,7 @@ export class AppMessagesManager {
if(historyUpdated.unread) { if(historyUpdated.unread) {
foundDialog.unread_count -= historyUpdated.unread; foundDialog.unread_count -= historyUpdated.unread;
rootScope.broadcast('dialog_unread', { rootScope.broadcast('dialog_unread', {peerId});
peerId,
count: foundDialog.unread_count
});
} }
if(historyUpdated.msgs[foundDialog.top_message]) { 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]) { if(this.migratedFromTo[peerId]) {
peerId = this.migratedFromTo[peerId]; peerId = this.migratedFromTo[peerId];
} }
const historyStorage = this.getHistoryStorage(peerId); const historyStorage = this.getHistoryStorage(peerId, threadId);
const unreadOffset = 0; const unreadOffset = 0;
const unreadSkip = false; const unreadSkip = false;
@ -4126,7 +4197,7 @@ export class AppMessagesManager {
limit += backLimit; 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; historyStorage.count = (historyResult as MessagesMessages.messagesMessagesSlice).count || historyResult.messages.length;
if(isMigrated) { if(isMigrated) {
historyStorage.count++; 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; offset = 0;
if(maxId > 0) { if(maxId > 0) {
for(offset = 0; offset < historyStorage.history.length; offset++) { 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)) // this.log('fill history storage', peerId, maxId, fullLimit, angular.copy(historyStorage))
const offset = (this.migratedFromTo[peerId] && !maxId) ? 1 : 0; 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; historyStorage.count = (historyResult as MessagesMessages.messagesMessagesSlice).count || historyResult.messages.length;
if(!maxId && 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) { } 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; 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); const isChannel = appPeersManager.isChannel(peerId);
//console.trace('requestHistory', peerId, maxId, limit, offset); //console.trace('requestHistory', peerId, maxId, limit, offset);
//rootScope.broadcast('history_request'); //rootScope.broadcast('history_request');
const promise = apiManager.invokeApi('messages.getHistory', { const options = {
peer: appPeersManager.getInputPeerById(peerId), peer: appPeersManager.getInputPeerById(peerId),
msg_id: threadId,
offset_id: this.getLocalMessageId(maxId) || 0, offset_id: this.getLocalMessageId(maxId) || 0,
offset_date: offsetDate, offset_date: offsetDate,
add_offset: offset, add_offset: offset,
@ -4267,18 +4339,16 @@ export class AppMessagesManager {
max_id: 0, max_id: 0,
min_id: 0, min_id: 0,
hash: 0 hash: 0
}, { };
const promise: ReturnType<AppMessagesManager['requestHistory']> = apiManager.invokeApi(threadId ? 'messages.getReplies' : 'messages.getHistory', options, {
//timeout: APITIMEOUT, //timeout: APITIMEOUT,
noErrorBox: true noErrorBox: true
}) as ReturnType<AppMessagesManager['requestHistory']>; }) as any;
return promise.then((historyResult) => { return promise.then((historyResult) => {
this.log('requestHistory result:', peerId, historyResult, maxId, limit, offset); this.log('requestHistory result:', peerId, historyResult, maxId, limit, offset);
/* if(historyResult._ == 'messages.messagesNotModified') {
return historyResult as any;
} */
appUsersManager.saveApiUsers(historyResult.users); appUsersManager.saveApiUsers(historyResult.users);
appChatsManager.saveApiChats(historyResult.chats); appChatsManager.saveApiChats(historyResult.chats);
this.saveMessages(historyResult.messages); 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) // 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 // historyResult.messages: desc sorted
if(length && (historyResult.messages[length - 1] as Message.message).grouped_id if(length && (historyResult.messages[length - 1] as Message.message).grouped_id
&& (historyStorage.history.length + historyResult.messages.length) < (historyResult as MessagesMessages.messagesMessagesSlice).count) { && (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; 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 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) => { }, (error) => {
switch (error.type) { switch (error.type) {
case 'CHANNEL_PRIVATE': case 'CHANNEL_PRIVATE':

2
src/lib/rootScope.ts

@ -20,7 +20,7 @@ type BroadcastEvents = {
'filter_order': number[], 'filter_order': number[],
'dialog_draft': {peerId: number, draft: any, index: number}, 'dialog_draft': {peerId: number, draft: any, index: number},
'dialog_unread': {peerId: number, count?: number}, 'dialog_unread': {peerId: number},
'dialog_flush': {peerId: number}, 'dialog_flush': {peerId: number},
'dialog_drop': {peerId: number, dialog?: Dialog}, 'dialog_drop': {peerId: number, dialog?: Dialog},
'dialog_migrate': {migrateFrom: number, migrateTo: number}, 'dialog_migrate': {migrateFrom: number, migrateTo: number},

5
src/scss/partials/_avatar.scss

@ -107,4 +107,9 @@ avatar-element {
--size: 32px; --size: 32px;
--multiplier: 1.6875; --multiplier: 1.6875;
} }
&.avatar-18 {
--size: 18px;
--multiplier: 3;
}
} }

84
src/scss/partials/_chatBubble.scss

@ -714,7 +714,8 @@ $bubble-margin: .25rem;
} }
.web { .web {
margin-top: -6px !important; padding-top: 1px;
margin: 4px 0 -5px 1px;
// margin-bottom: 5px; // margin-bottom: 5px;
max-width: 100%; max-width: 100%;
overflow: hidden; overflow: hidden;
@ -775,11 +776,6 @@ $bubble-margin: .25rem;
.web, .reply { .web, .reply {
font-size: .95rem; font-size: .95rem;
// margin: .25rem;
margin: 4px 4px 0 6px;
//padding: .25rem;
padding: 4px;
border-radius: 4px;
//transition: anim(background-color); //transition: anim(background-color);
/* &:hover { /* &:hover {
@ -829,9 +825,10 @@ $bubble-margin: .25rem;
} }
.reply { .reply {
margin-bottom: 6px; padding: 4px;
margin-top: 0; margin: 0 4px 6px 4px;
cursor: pointer; cursor: pointer;
border-radius: 4px;
&-content { &-content {
max-width: 300px; max-width: 300px;
@ -881,6 +878,7 @@ $bubble-margin: .25rem;
line-height: 21px; line-height: 21px;
word-break: break-word; word-break: break-word;
white-space: pre-wrap; // * fix spaces on line begin white-space: pre-wrap; // * fix spaces on line begin
position: relative;
/* * { /* * {
overflow: hidden; overflow: hidden;
@ -1479,6 +1477,70 @@ $bubble-margin: .25rem;
audio-element, poll-element { audio-element, poll-element {
white-space: normal; // * fix due to .message white-space prewrap 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 // * fix scroll with only 1 bubble
@ -1988,7 +2050,7 @@ $bubble-margin: .25rem;
} }
&.is-link:before { &.is-link:before {
content: $tgico-next; content: $tgico-arrow-next;
position: absolute; position: absolute;
right: 2px; right: 2px;
top: 2px; top: 2px;
@ -2251,11 +2313,7 @@ poll-element {
} }
avatar-element { avatar-element {
width: 18px;
height: 18px;
border: 1px solid #fff; border: 1px solid #fff;
line-height: 20px;
font-size: 10px;
cursor: pointer; cursor: pointer;
} }

2
src/scss/partials/_fonts.scss

@ -366,7 +366,7 @@
.tgico-forward:before { .tgico-forward:before {
content: "\e96d"; content: "\e96d";
} }
.tgico-next:before { .tgico-arrow-next:before {
content: "\e96e"; content: "\e96e";
} }
.tgico-unlock:before { .tgico-unlock:before {

2
src/scss/partials/_ico.scss

@ -123,7 +123,7 @@ $tgico-play: "\e96a";
$tgico-pause: "\e96b"; $tgico-pause: "\e96b";
$tgico-reply: "\e96c"; $tgico-reply: "\e96c";
$tgico-forward: "\e96d"; $tgico-forward: "\e96d";
$tgico-next: "\e96e"; $tgico-arrow-next: "\e96e";
$tgico-unlock: "\e96f"; $tgico-unlock: "\e96f";
$tgico-lock: "\e970"; $tgico-lock: "\e970";
$tgico-data: "\e971"; $tgico-data: "\e971";

91
src/scss/partials/popups/_datePicker.scss

@ -79,15 +79,7 @@
width: 100%; width: 100%;
justify-content: center; justify-content: center;
span, .btn-icon { .btn-icon {
// justify-self: center;
// width: 40px;
// height: 40px;
// font-size: 1rem;
// color: #707579;
// display: flex;
// justify-content: center;
// align-items: center;
justify-self: center; justify-self: center;
width: 38px; width: 38px;
height: 38px; height: 38px;
@ -96,6 +88,14 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
&:disabled {
opacity: 1;
}
}
&-date:disabled {
color: #c2c3c4;
} }
.btn-icon:not(:disabled) { .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…
Cancel
Save