Bot keyboard
Display 'via @username'
This commit is contained in:
parent
706bf9fd27
commit
01ec2005e9
@ -43,7 +43,7 @@ export default class BubbleGroups {
|
|||||||
|
|
||||||
const timestamp = message.date;
|
const timestamp = message.date;
|
||||||
const mid = message.mid;
|
const mid = message.mid;
|
||||||
let fromId = message.fromId;
|
let fromId = message.viaBotId || message.fromId;
|
||||||
let group: Group;
|
let group: Group;
|
||||||
|
|
||||||
// fix for saved messages forward to self
|
// fix for saved messages forward to self
|
||||||
|
@ -2583,14 +2583,17 @@ export default class ChatBubbles {
|
|||||||
|
|
||||||
let savedFrom = '';
|
let savedFrom = '';
|
||||||
|
|
||||||
const needName = (peerId < 0 && (peerId !== message.fromId || our)) && message.fromId !== rootScope.myId;
|
const needName = ((peerId < 0 && (peerId !== message.fromId || our)) && message.fromId !== rootScope.myId) || message.viaBotId;
|
||||||
if(needName || message.fwd_from || message.reply_to_mid) { // chat
|
if(needName || message.fwd_from || message.reply_to_mid) { // chat
|
||||||
let title: HTMLSpanElement;
|
let title: HTMLSpanElement;
|
||||||
|
|
||||||
const isForwardFromChannel = message.from_id && message.from_id._ === 'peerChannel' && message.fromId === message.fwdFromId;
|
const isForwardFromChannel = message.from_id && message.from_id._ === 'peerChannel' && message.fromId === message.fwdFromId;
|
||||||
|
|
||||||
let isHidden = message.fwd_from && !message.fwd_from.from_id && !message.fwd_from.channel_id;
|
let isHidden = message.fwd_from && !message.fwd_from.from_id && !message.fwd_from.channel_id;
|
||||||
if(isHidden) {
|
if(message.viaBotId) {
|
||||||
|
title = document.createElement('span');
|
||||||
|
title.innerText = '@' + this.appUsersManager.getUser(message.viaBotId).username;
|
||||||
|
} else if(isHidden) {
|
||||||
///////this.log('message to render hidden', message);
|
///////this.log('message to render hidden', message);
|
||||||
title = document.createElement('span');
|
title = document.createElement('span');
|
||||||
title.innerHTML = RichTextProcessor.wrapEmojiText(message.fwd_from.from_name);
|
title.innerHTML = RichTextProcessor.wrapEmojiText(message.fwd_from.from_name);
|
||||||
@ -2598,12 +2601,22 @@ export default class ChatBubbles {
|
|||||||
//title = message.fwd_from.from_name;
|
//title = message.fwd_from.from_name;
|
||||||
bubble.classList.add('hidden-profile');
|
bubble.classList.add('hidden-profile');
|
||||||
} else {
|
} else {
|
||||||
title = new PeerTitle({peerId: message.fwdFromId || message.fromId}).element;
|
title = new PeerTitle({peerId: message.viaBotId || message.fwdFromId || message.fromId}).element;
|
||||||
}
|
}
|
||||||
|
|
||||||
//this.log(title);
|
//this.log(title);
|
||||||
|
|
||||||
if((message.fwdFromId || message.fwd_from)) {
|
if(message.viaBotId) {
|
||||||
|
if(!bubble.classList.contains('sticker')) {
|
||||||
|
let nameDiv = document.createElement('div');
|
||||||
|
nameDiv.classList.add('name');
|
||||||
|
nameDiv.dataset.peerId = message.viaBotId;
|
||||||
|
nameDiv.append(i18n('ViaBot'), ' ', title);
|
||||||
|
nameContainer.append(nameDiv);
|
||||||
|
} else {
|
||||||
|
bubble.classList.add('hide-name');
|
||||||
|
}
|
||||||
|
} else if((message.fwdFromId || message.fwd_from)) {
|
||||||
if(this.peerId !== rootScope.myId && !isForwardFromChannel) {
|
if(this.peerId !== rootScope.myId && !isForwardFromChannel) {
|
||||||
bubble.classList.add('forwarded');
|
bubble.classList.add('forwarded');
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@ import AutocompleteHelper from './autocompleteHelper';
|
|||||||
import MentionsHelper from './mentionsHelper';
|
import MentionsHelper from './mentionsHelper';
|
||||||
import fixSafariStickyInput from '../../helpers/dom/fixSafariStickyInput';
|
import fixSafariStickyInput from '../../helpers/dom/fixSafariStickyInput';
|
||||||
import { emojiFromCodePoints } from '../../vendor/emoji';
|
import { emojiFromCodePoints } from '../../vendor/emoji';
|
||||||
|
import ReplyKeyboard from './replyKeyboard';
|
||||||
|
|
||||||
const RECORD_MIN_TIME = 500;
|
const RECORD_MIN_TIME = 500;
|
||||||
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
||||||
@ -88,8 +89,11 @@ export default class ChatInput {
|
|||||||
public rowsWrapper: HTMLDivElement;
|
public rowsWrapper: HTMLDivElement;
|
||||||
private newMessageWrapper: HTMLDivElement;
|
private newMessageWrapper: HTMLDivElement;
|
||||||
private btnToggleEmoticons: HTMLButtonElement;
|
private btnToggleEmoticons: HTMLButtonElement;
|
||||||
|
private btnToggleReplyMarkup: HTMLButtonElement;
|
||||||
private btnSendContainer: HTMLDivElement;
|
private btnSendContainer: HTMLDivElement;
|
||||||
|
|
||||||
|
private replyKeyboard: ReplyKeyboard;
|
||||||
|
|
||||||
private attachMenu: HTMLButtonElement;
|
private attachMenu: HTMLButtonElement;
|
||||||
private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerId: number) => boolean})[];
|
private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerId: number) => boolean})[];
|
||||||
|
|
||||||
@ -294,8 +298,7 @@ export default class ChatInput {
|
|||||||
this.goDownUnreadBadge.classList.add('badge', 'badge-24', 'badge-primary');
|
this.goDownUnreadBadge.classList.add('badge', 'badge-24', 'badge-primary');
|
||||||
this.goDownBtn.append(this.goDownUnreadBadge);
|
this.goDownBtn.append(this.goDownUnreadBadge);
|
||||||
|
|
||||||
this.btnScheduled = ButtonIcon('scheduled', {noRipple: true});
|
this.btnScheduled = ButtonIcon('scheduled btn-scheduled float hide', {noRipple: true});
|
||||||
this.btnScheduled.classList.add('btn-scheduled', 'hide');
|
|
||||||
|
|
||||||
attachClickEvent(this.btnScheduled, (e) => {
|
attachClickEvent(this.btnScheduled, (e) => {
|
||||||
this.appImManager.openScheduled(this.chat.peerId);
|
this.appImManager.openScheduled(this.chat.peerId);
|
||||||
@ -322,6 +325,16 @@ export default class ChatInput {
|
|||||||
this.btnScheduled.classList.toggle('hide', !value.length);
|
this.btnScheduled.classList.toggle('hide', !value.length);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.btnToggleReplyMarkup = ButtonIcon('botcom toggle-reply-markup float hide', {noRipple: true});
|
||||||
|
this.replyKeyboard = new ReplyKeyboard({
|
||||||
|
appendTo: this.rowsWrapper,
|
||||||
|
listenerSetter: this.listenerSetter,
|
||||||
|
appMessagesManager: this.appMessagesManager,
|
||||||
|
btnHover: this.btnToggleReplyMarkup
|
||||||
|
});
|
||||||
|
this.listenerSetter.add(this.replyKeyboard, 'open', () => this.btnToggleReplyMarkup.classList.add('active'));
|
||||||
|
this.listenerSetter.add(this.replyKeyboard, 'close', () => this.btnToggleReplyMarkup.classList.remove('active'));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.attachMenuButtons = [{
|
this.attachMenuButtons = [{
|
||||||
@ -367,7 +380,7 @@ export default class ChatInput {
|
|||||||
this.fileInput.multiple = true;
|
this.fileInput.multiple = true;
|
||||||
this.fileInput.style.display = 'none';
|
this.fileInput.style.display = 'none';
|
||||||
|
|
||||||
this.newMessageWrapper.append(...[this.btnToggleEmoticons, this.inputMessageContainer, this.btnScheduled, this.attachMenu, this.recordTimeEl, this.fileInput].filter(Boolean));
|
this.newMessageWrapper.append(...[this.btnToggleEmoticons, this.inputMessageContainer, this.btnScheduled, this.btnToggleReplyMarkup, this.attachMenu, this.recordTimeEl, this.fileInput].filter(Boolean));
|
||||||
|
|
||||||
this.rowsWrapper.append(this.replyElements.container);
|
this.rowsWrapper.append(this.replyElements.container);
|
||||||
this.autocompleteHelperController = new AutocompleteHelperController();
|
this.autocompleteHelperController = new AutocompleteHelperController();
|
||||||
@ -418,8 +431,8 @@ export default class ChatInput {
|
|||||||
this.inputContainer.append(this.btnCancelRecord, this.btnSendContainer);
|
this.inputContainer.append(this.btnCancelRecord, this.btnSendContainer);
|
||||||
|
|
||||||
emoticonsDropdown.attachButtonListener(this.btnToggleEmoticons, this.listenerSetter);
|
emoticonsDropdown.attachButtonListener(this.btnToggleEmoticons, this.listenerSetter);
|
||||||
emoticonsDropdown.events.onOpen.push(this.onEmoticonsOpen);
|
this.listenerSetter.add(emoticonsDropdown, 'open', this.onEmoticonsOpen);
|
||||||
emoticonsDropdown.events.onClose.push(this.onEmoticonsClose);
|
this.listenerSetter.add(emoticonsDropdown, 'close', this.onEmoticonsClose);
|
||||||
|
|
||||||
this.attachMessageInputField();
|
this.attachMessageInputField();
|
||||||
|
|
||||||
@ -651,9 +664,6 @@ 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.onClose.findAndSplice(f => f === this.onEmoticonsClose);
|
|
||||||
|
|
||||||
this.listenerSetter.removeAll();
|
this.listenerSetter.removeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -720,6 +730,10 @@ export default class ChatInput {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this.replyKeyboard) {
|
||||||
|
this.replyKeyboard.setPeer(peerId);
|
||||||
|
}
|
||||||
|
|
||||||
if(this.sendMenu) {
|
if(this.sendMenu) {
|
||||||
this.sendMenu.setPeerId(peerId);
|
this.sendMenu.setPeerId(peerId);
|
||||||
}
|
}
|
||||||
@ -1479,6 +1493,10 @@ export default class ChatInput {
|
|||||||
if(this.btnScheduled) {
|
if(this.btnScheduled) {
|
||||||
this.btnScheduled.classList.toggle('show', isInputEmpty);
|
this.btnScheduled.classList.toggle('show', isInputEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this.btnToggleReplyMarkup) {
|
||||||
|
this.btnToggleReplyMarkup.classList.toggle('show', isInputEmpty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMessageSent(clearInput = true, clearReply?: boolean) {
|
public onMessageSent(clearInput = true, clearReply?: boolean) {
|
||||||
|
108
src/components/chat/replyKeyboard.ts
Normal file
108
src/components/chat/replyKeyboard.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { AppMessagesManager } from "../../lib/appManagers/appMessagesManager";
|
||||||
|
import DropdownHover from "../../helpers/dropdownHover";
|
||||||
|
import { ReplyMarkup } from "../../layer";
|
||||||
|
import RichTextProcessor from "../../lib/richtextprocessor";
|
||||||
|
import rootScope from "../../lib/rootScope";
|
||||||
|
import { safeAssign } from "../../helpers/object";
|
||||||
|
import ListenerSetter from "../../helpers/listenerSetter";
|
||||||
|
import findUpClassName from "../../helpers/dom/findUpClassName";
|
||||||
|
|
||||||
|
export default class ReplyKeyboard extends DropdownHover {
|
||||||
|
private static BASE_CLASS = 'reply-keyboard';
|
||||||
|
private appendTo: HTMLElement;
|
||||||
|
private listenerSetter: ListenerSetter;
|
||||||
|
private appMessagesManager: AppMessagesManager;
|
||||||
|
private btnHover: HTMLElement;
|
||||||
|
private peerId: number;
|
||||||
|
|
||||||
|
constructor(options: {
|
||||||
|
listenerSetter: ListenerSetter,
|
||||||
|
appMessagesManager: AppMessagesManager,
|
||||||
|
appendTo: HTMLElement,
|
||||||
|
btnHover: HTMLElement
|
||||||
|
}) {
|
||||||
|
super({
|
||||||
|
element: document.createElement('div')
|
||||||
|
});
|
||||||
|
|
||||||
|
safeAssign(this, options);
|
||||||
|
|
||||||
|
this.element.classList.add(ReplyKeyboard.BASE_CLASS);
|
||||||
|
this.element.style.display = 'none';
|
||||||
|
|
||||||
|
this.attachButtonListener(this.btnHover, this.listenerSetter);
|
||||||
|
this.listenerSetter.add(rootScope, 'history_reply_markup', ({peerId}) => {
|
||||||
|
if(this.peerId === peerId && this.checkAvailability() && this.isActive()) {
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected init() {
|
||||||
|
this.appendTo.append(this.element);
|
||||||
|
|
||||||
|
this.listenerSetter.add(this, 'open', () => {
|
||||||
|
this.render();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.listenerSetter.add(this.element, 'click', (e) => {
|
||||||
|
const target = findUpClassName(e.target, 'btn');
|
||||||
|
if(!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.appMessagesManager.sendText(this.peerId, target.dataset.text);
|
||||||
|
this.toggle(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
return super.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private getReplyMarkup(): ReplyMarkup {
|
||||||
|
return this.appMessagesManager.getHistoryStorage(this.peerId).reply_markup ?? {
|
||||||
|
_: 'replyKeyboardHide'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(replyMarkup: ReplyMarkup.replyKeyboardMarkup = this.getReplyMarkup() as any) {
|
||||||
|
this.element.innerHTML = '';
|
||||||
|
|
||||||
|
for(const row of replyMarkup.rows) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.classList.add(ReplyKeyboard.BASE_CLASS + '-row');
|
||||||
|
|
||||||
|
for(const button of row.buttons) {
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
btn.classList.add(ReplyKeyboard.BASE_CLASS + '-button', 'btn');
|
||||||
|
btn.innerHTML = RichTextProcessor.wrapEmojiText(button.text);
|
||||||
|
btn.dataset.text = button.text;
|
||||||
|
div.append(btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.append(div);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public checkAvailability(replyMarkup: ReplyMarkup = this.getReplyMarkup()) {
|
||||||
|
const hide = replyMarkup._ === 'replyKeyboardHide';
|
||||||
|
this.btnHover.classList.toggle('hide', hide);
|
||||||
|
|
||||||
|
if(hide) {
|
||||||
|
this.toggle(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !hide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setPeer(peerId: number) {
|
||||||
|
this.peerId = peerId;
|
||||||
|
|
||||||
|
this.checkAvailability();
|
||||||
|
}
|
||||||
|
}
|
@ -23,11 +23,10 @@ import AppGifsTab from "../sidebarRight/tabs/gifs";
|
|||||||
import AppStickersTab from "../sidebarRight/tabs/stickers";
|
import AppStickersTab from "../sidebarRight/tabs/stickers";
|
||||||
import findUpClassName from "../../helpers/dom/findUpClassName";
|
import findUpClassName from "../../helpers/dom/findUpClassName";
|
||||||
import findUpTag from "../../helpers/dom/findUpTag";
|
import findUpTag from "../../helpers/dom/findUpTag";
|
||||||
import ListenerSetter from "../../helpers/listenerSetter";
|
|
||||||
import blurActiveElement from "../../helpers/dom/blurActiveElement";
|
import blurActiveElement from "../../helpers/dom/blurActiveElement";
|
||||||
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
|
||||||
import whichChild from "../../helpers/dom/whichChild";
|
import whichChild from "../../helpers/dom/whichChild";
|
||||||
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
||||||
|
import DropdownHover from "../../helpers/dropdownHover";
|
||||||
|
|
||||||
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
|
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
|
||||||
|
|
||||||
@ -36,13 +35,8 @@ export interface EmoticonsTab {
|
|||||||
onCloseAfterTimeout?: () => void
|
onCloseAfterTimeout?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const KEEP_OPEN = false;
|
export class EmoticonsDropdown extends DropdownHover {
|
||||||
const TOGGLE_TIMEOUT = 200;
|
|
||||||
const ANIMATION_DURATION = 200;
|
|
||||||
|
|
||||||
export class EmoticonsDropdown {
|
|
||||||
public static lazyLoadQueue = new LazyLoadQueue();
|
public static lazyLoadQueue = new LazyLoadQueue();
|
||||||
private element: HTMLElement;
|
|
||||||
|
|
||||||
private emojiTab: EmojiTab;
|
private emojiTab: EmojiTab;
|
||||||
public stickersTab: StickersTab;
|
public stickersTab: StickersTab;
|
||||||
@ -56,73 +50,70 @@ export class EmoticonsDropdown {
|
|||||||
|
|
||||||
private searchButton: HTMLElement;
|
private searchButton: HTMLElement;
|
||||||
private deleteBtn: HTMLElement;
|
private deleteBtn: HTMLElement;
|
||||||
|
|
||||||
private displayTimeout: number;
|
|
||||||
|
|
||||||
public events: {
|
|
||||||
onClose: Array<() => void>,
|
|
||||||
onCloseAfter: Array<() => void>,
|
|
||||||
onOpen: Array<() => void>,
|
|
||||||
onOpenAfter: Array<() => void>
|
|
||||||
} = {
|
|
||||||
onClose: [],
|
|
||||||
onCloseAfter: [],
|
|
||||||
onOpen: [],
|
|
||||||
onOpenAfter: []
|
|
||||||
};
|
|
||||||
|
|
||||||
private selectTab: ReturnType<typeof horizontalMenu>;
|
private selectTab: ReturnType<typeof horizontalMenu>;
|
||||||
private forceClose = false;
|
|
||||||
|
|
||||||
private savedRange: Range;
|
private savedRange: Range;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.element = document.getElementById('emoji-dropdown') as HTMLDivElement;
|
super({
|
||||||
|
element: document.getElementById('emoji-dropdown') as HTMLDivElement
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener('open', async() => {
|
||||||
|
if(isTouchSupported) {
|
||||||
|
//appImManager.chat.input.saveScroll();
|
||||||
|
if(blurActiveElement()) {
|
||||||
|
await pause(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.element.parentElement !== appImManager.chat.input.chatInput) {
|
||||||
|
appImManager.chat.input.chatInput.append(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sel = document.getSelection();
|
||||||
|
if(sel.rangeCount && document.activeElement === appImManager.chat.input.messageInput) {
|
||||||
|
this.savedRange = sel.getRangeAt(0);
|
||||||
|
} else {
|
||||||
|
this.savedRange = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
EmoticonsDropdown.lazyLoadQueue.lock();
|
||||||
|
//EmoticonsDropdown.lazyLoadQueue.unlock();
|
||||||
|
animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener('opened', () => {
|
||||||
|
animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
||||||
|
EmoticonsDropdown.lazyLoadQueue.unlock();
|
||||||
|
EmoticonsDropdown.lazyLoadQueue.refresh();
|
||||||
|
|
||||||
|
this.container.classList.remove('disable-hover');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener('close', () => {
|
||||||
|
EmoticonsDropdown.lazyLoadQueue.lock();
|
||||||
|
//EmoticonsDropdown.lazyLoadQueue.lock();
|
||||||
|
|
||||||
|
// нужно залочить группу и выключить стикеры
|
||||||
|
animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
||||||
|
animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addEventListener('closed', () => {
|
||||||
|
// теперь можно убрать visible, чтобы они не включились после фокуса
|
||||||
|
animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
||||||
|
EmoticonsDropdown.lazyLoadQueue.unlock();
|
||||||
|
EmoticonsDropdown.lazyLoadQueue.refresh();
|
||||||
|
|
||||||
|
this.container.classList.remove('disable-hover');
|
||||||
|
|
||||||
|
this.savedRange = undefined;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public attachButtonListener(button: HTMLElement, listenerSetter: ListenerSetter) {
|
protected init() {
|
||||||
let firstTime = true;
|
|
||||||
if(isTouchSupported) {
|
|
||||||
attachClickEvent(button, () => {
|
|
||||||
if(firstTime) {
|
|
||||||
firstTime = false;
|
|
||||||
this.toggle(true);
|
|
||||||
} else {
|
|
||||||
this.toggle();
|
|
||||||
}
|
|
||||||
}, {listenerSetter});
|
|
||||||
} else {
|
|
||||||
listenerSetter.add(button, 'mouseover', (e) => {
|
|
||||||
//console.log('onmouseover button');
|
|
||||||
if(firstTime) {
|
|
||||||
listenerSetter.add(button, 'mouseout', this.onMouseOut);
|
|
||||||
firstTime = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearTimeout(this.displayTimeout);
|
|
||||||
this.displayTimeout = window.setTimeout(() => {
|
|
||||||
this.toggle(true);
|
|
||||||
}, TOGGLE_TIMEOUT);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private onMouseOut = (e: MouseEvent) => {
|
|
||||||
if(KEEP_OPEN) return;
|
|
||||||
clearTimeout(this.displayTimeout);
|
|
||||||
if(!this.element.classList.contains('active')) return;
|
|
||||||
|
|
||||||
const toElement = (e as any).toElement as Element;
|
|
||||||
if(toElement && findUpClassName(toElement, 'emoji-dropdown')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.displayTimeout = window.setTimeout(() => {
|
|
||||||
this.toggle(false);
|
|
||||||
}, TOGGLE_TIMEOUT);
|
|
||||||
};
|
|
||||||
|
|
||||||
private init() {
|
|
||||||
this.emojiTab = new EmojiTab();
|
this.emojiTab = new EmojiTab();
|
||||||
this.stickersTab = new StickersTab();
|
this.stickersTab = new StickersTab();
|
||||||
this.gifsTab = new GifsTab();
|
this.gifsTab = new GifsTab();
|
||||||
@ -186,17 +177,7 @@ export class EmoticonsDropdown {
|
|||||||
rootScope.addEventListener('peer_changed', this.checkRights);
|
rootScope.addEventListener('peer_changed', this.checkRights);
|
||||||
this.checkRights();
|
this.checkRights();
|
||||||
|
|
||||||
if(!isTouchSupported) {
|
return super.init();
|
||||||
this.element.onmouseout = this.onMouseOut;
|
|
||||||
this.element.onmouseover = (e) => {
|
|
||||||
if(this.forceClose) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.log('onmouseover element');
|
|
||||||
clearTimeout(this.displayTimeout);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onSelectTabClick = (id: number) => {
|
private onSelectTabClick = (id: number) => {
|
||||||
@ -228,116 +209,6 @@ export class EmoticonsDropdown {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public toggle = async(enable?: boolean) => {
|
|
||||||
//if(!this.element) return;
|
|
||||||
const willBeActive = (!!this.element.style.display && enable === undefined) || enable;
|
|
||||||
if(this.init) {
|
|
||||||
if(willBeActive) {
|
|
||||||
this.init();
|
|
||||||
this.init = null;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isTouchSupported) {
|
|
||||||
if(willBeActive) {
|
|
||||||
//appImManager.chat.input.saveScroll();
|
|
||||||
if(blurActiveElement()) {
|
|
||||||
await pause(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.element.parentElement !== appImManager.chat.input.chatInput) {
|
|
||||||
appImManager.chat.input.chatInput.append(this.element);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((this.element.style.display && enable === undefined) || enable) {
|
|
||||||
this.events.onOpen.forEach(cb => cb());
|
|
||||||
|
|
||||||
const sel = document.getSelection();
|
|
||||||
if(sel.rangeCount && document.activeElement === appImManager.chat.input.messageInput) {
|
|
||||||
this.savedRange = sel.getRangeAt(0);
|
|
||||||
} else {
|
|
||||||
this.savedRange = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
EmoticonsDropdown.lazyLoadQueue.lock();
|
|
||||||
//EmoticonsDropdown.lazyLoadQueue.unlock();
|
|
||||||
animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
|
||||||
|
|
||||||
this.element.style.display = '';
|
|
||||||
void this.element.offsetLeft; // reflow
|
|
||||||
this.element.classList.add('active');
|
|
||||||
|
|
||||||
clearTimeout(this.displayTimeout);
|
|
||||||
this.displayTimeout = window.setTimeout(() => {
|
|
||||||
animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
|
||||||
EmoticonsDropdown.lazyLoadQueue.unlock();
|
|
||||||
EmoticonsDropdown.lazyLoadQueue.refresh();
|
|
||||||
|
|
||||||
this.forceClose = false;
|
|
||||||
this.container.classList.remove('disable-hover');
|
|
||||||
|
|
||||||
this.events.onOpenAfter.forEach(cb => cb());
|
|
||||||
}, isTouchSupported ? 0 : ANIMATION_DURATION);
|
|
||||||
|
|
||||||
// ! can't use together with resizeObserver
|
|
||||||
/* if(isTouchSupported) {
|
|
||||||
const height = this.element.scrollHeight + appImManager.chat.input.inputContainer.scrollHeight - 10;
|
|
||||||
console.log('[ESG]: toggle: enable height', height);
|
|
||||||
appImManager.chat.bubbles.scrollable.scrollTop += height;
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* if(touchSupport) {
|
|
||||||
this.restoreScroll();
|
|
||||||
} */
|
|
||||||
} else {
|
|
||||||
this.events.onClose.forEach(cb => cb());
|
|
||||||
|
|
||||||
EmoticonsDropdown.lazyLoadQueue.lock();
|
|
||||||
//EmoticonsDropdown.lazyLoadQueue.lock();
|
|
||||||
|
|
||||||
// нужно залочить группу и выключить стикеры
|
|
||||||
animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
|
||||||
animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
|
||||||
|
|
||||||
this.element.classList.remove('active');
|
|
||||||
|
|
||||||
clearTimeout(this.displayTimeout);
|
|
||||||
this.displayTimeout = window.setTimeout(() => {
|
|
||||||
this.element.style.display = 'none';
|
|
||||||
|
|
||||||
// теперь можно убрать visible, чтобы они не включились после фокуса
|
|
||||||
animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);
|
|
||||||
EmoticonsDropdown.lazyLoadQueue.unlock();
|
|
||||||
EmoticonsDropdown.lazyLoadQueue.refresh();
|
|
||||||
|
|
||||||
this.forceClose = false;
|
|
||||||
this.container.classList.remove('disable-hover');
|
|
||||||
|
|
||||||
this.events.onCloseAfter.forEach(cb => cb());
|
|
||||||
|
|
||||||
this.savedRange = undefined;
|
|
||||||
}, isTouchSupported ? 0 : ANIMATION_DURATION);
|
|
||||||
|
|
||||||
/* if(isTouchSupported) {
|
|
||||||
const scrollHeight = this.container.scrollHeight;
|
|
||||||
if(scrollHeight) {
|
|
||||||
const height = this.container.scrollHeight + appImManager.chat.input.inputContainer.scrollHeight - 10;
|
|
||||||
appImManager.chat.bubbles.scrollable.scrollTop -= height;
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* if(touchSupport) {
|
|
||||||
this.restoreScroll();
|
|
||||||
} */
|
|
||||||
}
|
|
||||||
|
|
||||||
//animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
|
||||||
};
|
|
||||||
|
|
||||||
public static menuOnClick = (menu: HTMLElement, scroll: Scrollable, menuScroll?: ScrollableX) => {
|
public static menuOnClick = (menu: HTMLElement, scroll: Scrollable, menuScroll?: ScrollableX) => {
|
||||||
let prevId = 0;
|
let prevId = 0;
|
||||||
let jumpedTo = -1;
|
let jumpedTo = -1;
|
||||||
@ -431,11 +302,11 @@ export class EmoticonsDropdown {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public addLazyLoadQueueRepeat(lazyLoadQueue: LazyLoadQueueIntersector, processInvisibleDiv: (div: HTMLElement) => void) {
|
public addLazyLoadQueueRepeat(lazyLoadQueue: LazyLoadQueueIntersector, processInvisibleDiv: (div: HTMLElement) => void) {
|
||||||
this.events.onClose.push(() => {
|
this.addEventListener('close', () => {
|
||||||
lazyLoadQueue.lock();
|
lazyLoadQueue.lock();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.events.onCloseAfter.push(() => {
|
this.addEventListener('closed', () => {
|
||||||
const divs = lazyLoadQueue.intersector.getVisible();
|
const divs = lazyLoadQueue.intersector.getVisible();
|
||||||
|
|
||||||
for(const div of divs) {
|
for(const div of divs) {
|
||||||
@ -445,7 +316,7 @@ export class EmoticonsDropdown {
|
|||||||
lazyLoadQueue.intersector.clearVisible();
|
lazyLoadQueue.intersector.clearVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.events.onOpenAfter.push(() => {
|
this.addEventListener('opened', () => {
|
||||||
lazyLoadQueue.unlockAndRefresh();
|
lazyLoadQueue.unlockAndRefresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
3
src/helpers/assumeType.ts
Normal file
3
src/helpers/assumeType.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function assumeType<T>(x: unknown): asserts x is T {
|
||||||
|
return; // ¯\_(ツ)_/¯
|
||||||
|
}
|
163
src/helpers/dropdownHover.ts
Normal file
163
src/helpers/dropdownHover.ts
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { attachClickEvent } from "./dom/clickEvent";
|
||||||
|
import findUpAsChild from "./dom/findUpAsChild";
|
||||||
|
import EventListenerBase from "./eventListenerBase";
|
||||||
|
import ListenerSetter from "./listenerSetter";
|
||||||
|
import { safeAssign } from "./object";
|
||||||
|
import { isTouchSupported } from "./touchSupport";
|
||||||
|
|
||||||
|
const KEEP_OPEN = false;
|
||||||
|
const TOGGLE_TIMEOUT = 200;
|
||||||
|
const ANIMATION_DURATION = 200;
|
||||||
|
|
||||||
|
export default class DropdownHover extends EventListenerBase<{
|
||||||
|
open: () => Promise<any> | void,
|
||||||
|
opened: () => any,
|
||||||
|
close: () => any,
|
||||||
|
closed: () => any
|
||||||
|
}> {
|
||||||
|
protected element: HTMLElement;
|
||||||
|
protected displayTimeout: number;
|
||||||
|
protected forceClose = false;
|
||||||
|
protected inited = false;
|
||||||
|
|
||||||
|
constructor(options: {
|
||||||
|
element: DropdownHover['element']
|
||||||
|
}) {
|
||||||
|
super(false);
|
||||||
|
safeAssign(this, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public attachButtonListener(button: HTMLElement, listenerSetter: ListenerSetter) {
|
||||||
|
let firstTime = true;
|
||||||
|
if(isTouchSupported) {
|
||||||
|
attachClickEvent(button, () => {
|
||||||
|
if(firstTime) {
|
||||||
|
firstTime = false;
|
||||||
|
this.toggle(true);
|
||||||
|
} else {
|
||||||
|
this.toggle();
|
||||||
|
}
|
||||||
|
}, {listenerSetter});
|
||||||
|
} else {
|
||||||
|
listenerSetter.add(button, 'mouseover', (e) => {
|
||||||
|
//console.log('onmouseover button');
|
||||||
|
if(firstTime) {
|
||||||
|
listenerSetter.add(button, 'mouseout', this.onMouseOut);
|
||||||
|
firstTime = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(this.displayTimeout);
|
||||||
|
this.displayTimeout = window.setTimeout(() => {
|
||||||
|
this.toggle(true);
|
||||||
|
}, TOGGLE_TIMEOUT);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onMouseOut = (e: MouseEvent) => {
|
||||||
|
if(KEEP_OPEN) return;
|
||||||
|
clearTimeout(this.displayTimeout);
|
||||||
|
if(!this.isActive()) return;
|
||||||
|
|
||||||
|
const toElement = (e as any).toElement as Element;
|
||||||
|
if(toElement && findUpAsChild(toElement, this.element)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayTimeout = window.setTimeout(() => {
|
||||||
|
this.toggle(false);
|
||||||
|
}, TOGGLE_TIMEOUT);
|
||||||
|
};
|
||||||
|
|
||||||
|
protected init() {
|
||||||
|
if(!isTouchSupported) {
|
||||||
|
this.element.onmouseout = this.onMouseOut;
|
||||||
|
this.element.onmouseover = (e) => {
|
||||||
|
if(this.forceClose) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log('onmouseover element');
|
||||||
|
clearTimeout(this.displayTimeout);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggle = async(enable?: boolean) => {
|
||||||
|
//if(!this.element) return;
|
||||||
|
const willBeActive = (!!this.element.style.display && enable === undefined) || enable;
|
||||||
|
if(this.init) {
|
||||||
|
if(willBeActive) {
|
||||||
|
this.init();
|
||||||
|
this.init = null;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(willBeActive === this.isActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((this.element.style.display && enable === undefined) || enable) {
|
||||||
|
const res = this.dispatchEvent('open');
|
||||||
|
await Promise.all(res);
|
||||||
|
|
||||||
|
this.element.style.display = '';
|
||||||
|
void this.element.offsetLeft; // reflow
|
||||||
|
this.element.classList.add('active');
|
||||||
|
|
||||||
|
clearTimeout(this.displayTimeout);
|
||||||
|
this.displayTimeout = window.setTimeout(() => {
|
||||||
|
this.forceClose = false;
|
||||||
|
this.dispatchEvent('opened');
|
||||||
|
}, isTouchSupported ? 0 : ANIMATION_DURATION);
|
||||||
|
|
||||||
|
// ! can't use together with resizeObserver
|
||||||
|
/* if(isTouchSupported) {
|
||||||
|
const height = this.element.scrollHeight + appImManager.chat.input.inputContainer.scrollHeight - 10;
|
||||||
|
console.log('[ESG]: toggle: enable height', height);
|
||||||
|
appImManager.chat.bubbles.scrollable.scrollTop += height;
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* if(touchSupport) {
|
||||||
|
this.restoreScroll();
|
||||||
|
} */
|
||||||
|
} else {
|
||||||
|
this.dispatchEvent('close');
|
||||||
|
|
||||||
|
this.element.classList.remove('active');
|
||||||
|
|
||||||
|
clearTimeout(this.displayTimeout);
|
||||||
|
this.displayTimeout = window.setTimeout(() => {
|
||||||
|
this.element.style.display = 'none';
|
||||||
|
this.forceClose = false;
|
||||||
|
this.dispatchEvent('closed');
|
||||||
|
}, isTouchSupported ? 0 : ANIMATION_DURATION);
|
||||||
|
|
||||||
|
/* if(isTouchSupported) {
|
||||||
|
const scrollHeight = this.container.scrollHeight;
|
||||||
|
if(scrollHeight) {
|
||||||
|
const height = this.container.scrollHeight + appImManager.chat.input.inputContainer.scrollHeight - 10;
|
||||||
|
appImManager.chat.bubbles.scrollable.scrollTop -= height;
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* if(touchSupport) {
|
||||||
|
this.restoreScroll();
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
|
//animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||||
|
};
|
||||||
|
|
||||||
|
public isActive() {
|
||||||
|
return this.element.classList.contains('active');
|
||||||
|
}
|
||||||
|
}
|
@ -483,6 +483,7 @@ const lang = {
|
|||||||
"JoinByPeekChannelTitle": "Join Channel",
|
"JoinByPeekChannelTitle": "Join Channel",
|
||||||
"JoinByPeekGroupTitle": "Join Group",
|
"JoinByPeekGroupTitle": "Join Group",
|
||||||
"YouWereKicked": "you were removed",
|
"YouWereKicked": "you were removed",
|
||||||
|
"ViaBot": "via",
|
||||||
|
|
||||||
// * macos
|
// * macos
|
||||||
"AccountSettings.Filters": "Chat Folders",
|
"AccountSettings.Filters": "Chat Folders",
|
||||||
|
19
src/layer.d.ts
vendored
19
src/layer.d.ts
vendored
@ -857,7 +857,8 @@ export namespace Message {
|
|||||||
peerId?: number,
|
peerId?: number,
|
||||||
fromId?: number,
|
fromId?: number,
|
||||||
random_id?: string,
|
random_id?: string,
|
||||||
rReply?: string
|
rReply?: string,
|
||||||
|
viaBotId?: number
|
||||||
};
|
};
|
||||||
|
|
||||||
export type messageService = {
|
export type messageService = {
|
||||||
@ -884,7 +885,8 @@ export namespace Message {
|
|||||||
deleted?: boolean,
|
deleted?: boolean,
|
||||||
peerId?: number,
|
peerId?: number,
|
||||||
fromId?: number,
|
fromId?: number,
|
||||||
rReply?: string
|
rReply?: string,
|
||||||
|
viaBotId?: number
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3995,7 +3997,8 @@ export namespace ReplyMarkup {
|
|||||||
flags?: number,
|
flags?: number,
|
||||||
pFlags?: Partial<{
|
pFlags?: Partial<{
|
||||||
selective?: true,
|
selective?: true,
|
||||||
}>
|
}>,
|
||||||
|
mid?: number
|
||||||
};
|
};
|
||||||
|
|
||||||
export type replyKeyboardForceReply = {
|
export type replyKeyboardForceReply = {
|
||||||
@ -4004,7 +4007,10 @@ export namespace ReplyMarkup {
|
|||||||
pFlags?: Partial<{
|
pFlags?: Partial<{
|
||||||
single_use?: true,
|
single_use?: true,
|
||||||
selective?: true,
|
selective?: true,
|
||||||
}>
|
hidden?: true,
|
||||||
|
}>,
|
||||||
|
mid?: number,
|
||||||
|
fromId?: number
|
||||||
};
|
};
|
||||||
|
|
||||||
export type replyKeyboardMarkup = {
|
export type replyKeyboardMarkup = {
|
||||||
@ -4014,8 +4020,11 @@ export namespace ReplyMarkup {
|
|||||||
resize?: true,
|
resize?: true,
|
||||||
single_use?: true,
|
single_use?: true,
|
||||||
selective?: true,
|
selective?: true,
|
||||||
|
hidden?: true,
|
||||||
}>,
|
}>,
|
||||||
rows: Array<KeyboardButtonRow>
|
rows: Array<KeyboardButtonRow>,
|
||||||
|
mid?: number,
|
||||||
|
fromId?: number
|
||||||
};
|
};
|
||||||
|
|
||||||
export type replyInlineMarkup = {
|
export type replyInlineMarkup = {
|
||||||
|
@ -17,7 +17,7 @@ import { createPosterForVideo } from "../../helpers/files";
|
|||||||
import { copy, getObjectKeysAndSort } from "../../helpers/object";
|
import { copy, getObjectKeysAndSort } from "../../helpers/object";
|
||||||
import { randomLong } from "../../helpers/random";
|
import { randomLong } from "../../helpers/random";
|
||||||
import { splitStringByLength, limitSymbols, escapeRegExp } from "../../helpers/string";
|
import { splitStringByLength, limitSymbols, escapeRegExp } from "../../helpers/string";
|
||||||
import { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates } from "../../layer";
|
import { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates, ReplyMarkup } from "../../layer";
|
||||||
import { InvokeApiOptions } from "../../types";
|
import { InvokeApiOptions } from "../../types";
|
||||||
import I18n, { i18n, join, langPack, LangPackKey, _i18n } from "../langPack";
|
import I18n, { i18n, join, langPack, LangPackKey, _i18n } from "../langPack";
|
||||||
import { logger, LogTypes } from "../logger";
|
import { logger, LogTypes } from "../logger";
|
||||||
@ -56,6 +56,7 @@ import formatCallDuration from "../../helpers/formatCallDuration";
|
|||||||
import appAvatarsManager from "./appAvatarsManager";
|
import appAvatarsManager from "./appAvatarsManager";
|
||||||
import telegramMeWebManager from "../mtproto/telegramMeWebManager";
|
import telegramMeWebManager from "../mtproto/telegramMeWebManager";
|
||||||
import { getMiddleware } from "../../helpers/middleware";
|
import { getMiddleware } from "../../helpers/middleware";
|
||||||
|
import assumeType from "../../helpers/assumeType";
|
||||||
|
|
||||||
//console.trace('include');
|
//console.trace('include');
|
||||||
// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет
|
// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет
|
||||||
@ -74,7 +75,7 @@ export type HistoryStorage = {
|
|||||||
triedToReadMaxId?: number,
|
triedToReadMaxId?: number,
|
||||||
|
|
||||||
maxOutId?: number,
|
maxOutId?: number,
|
||||||
reply_markup?: any
|
reply_markup?: Exclude<ReplyMarkup, ReplyMarkup.replyInlineMarkup>
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HistoryResult = {
|
export type HistoryResult = {
|
||||||
@ -3025,19 +3026,24 @@ export class AppMessagesManager {
|
|||||||
) && !message.pFlags.is_outgoing;
|
) && !message.pFlags.is_outgoing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public mergeReplyKeyboard(historyStorage: HistoryStorage, message: any) {
|
public getReplyKeyboard(peerId: number) {
|
||||||
|
return this.getHistoryStorage(peerId).reply_markup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public mergeReplyKeyboard(historyStorage: HistoryStorage, message: Message.messageService | Message.message) {
|
||||||
// this.log('merge', message.mid, message.reply_markup, historyStorage.reply_markup)
|
// this.log('merge', message.mid, message.reply_markup, historyStorage.reply_markup)
|
||||||
if(!message.reply_markup &&
|
let messageReplyMarkup = (message as Message.message).reply_markup;
|
||||||
|
if(!messageReplyMarkup &&
|
||||||
!message.pFlags?.out &&
|
!message.pFlags?.out &&
|
||||||
!message.action) {
|
!(message as Message.messageService).action) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(message.reply_markup &&
|
|
||||||
message.reply_markup._ === 'replyInlineMarkup') {
|
if(messageReplyMarkup?._ === 'replyInlineMarkup') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var messageReplyMarkup = message.reply_markup;
|
|
||||||
var lastReplyMarkup = historyStorage.reply_markup;
|
const lastReplyMarkup = historyStorage.reply_markup;
|
||||||
if(messageReplyMarkup) {
|
if(messageReplyMarkup) {
|
||||||
if(lastReplyMarkup && lastReplyMarkup.mid >= message.mid) {
|
if(lastReplyMarkup && lastReplyMarkup.mid >= message.mid) {
|
||||||
return false;
|
return false;
|
||||||
@ -3049,15 +3055,19 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
if(historyStorage.maxOutId &&
|
if(historyStorage.maxOutId &&
|
||||||
message.mid < historyStorage.maxOutId &&
|
message.mid < historyStorage.maxOutId &&
|
||||||
messageReplyMarkup.pFlags.single_use) {
|
(messageReplyMarkup as ReplyMarkup.replyKeyboardMarkup | ReplyMarkup.replyKeyboardForceReply).pFlags.single_use) {
|
||||||
messageReplyMarkup.pFlags.hidden = true;
|
(messageReplyMarkup as ReplyMarkup.replyKeyboardMarkup | ReplyMarkup.replyKeyboardForceReply).pFlags.hidden = true;
|
||||||
}
|
}
|
||||||
messageReplyMarkup = Object.assign({
|
|
||||||
|
messageReplyMarkup.mid = message.mid;
|
||||||
|
/* messageReplyMarkup = Object.assign({
|
||||||
mid: message.mid
|
mid: message.mid
|
||||||
}, messageReplyMarkup);
|
}, messageReplyMarkup); */
|
||||||
|
|
||||||
if(messageReplyMarkup._ !== 'replyKeyboardHide') {
|
if(messageReplyMarkup._ !== 'replyKeyboardHide') {
|
||||||
messageReplyMarkup.fromId = appPeersManager.getPeerId(message.from_id);
|
messageReplyMarkup.fromId = appPeersManager.getPeerId(message.from_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
historyStorage.reply_markup = messageReplyMarkup;
|
historyStorage.reply_markup = messageReplyMarkup;
|
||||||
// this.log('set', historyStorage.reply_markup)
|
// this.log('set', historyStorage.reply_markup)
|
||||||
return true;
|
return true;
|
||||||
@ -3065,10 +3075,11 @@ export class AppMessagesManager {
|
|||||||
|
|
||||||
if(message.pFlags.out) {
|
if(message.pFlags.out) {
|
||||||
if(lastReplyMarkup) {
|
if(lastReplyMarkup) {
|
||||||
|
assumeType<ReplyMarkup.replyKeyboardMarkup>(lastReplyMarkup);
|
||||||
if(lastReplyMarkup.pFlags.single_use &&
|
if(lastReplyMarkup.pFlags.single_use &&
|
||||||
!lastReplyMarkup.pFlags.hidden &&
|
!lastReplyMarkup.pFlags.hidden &&
|
||||||
(message.mid > lastReplyMarkup.mid || message.pFlags.is_outgoing) &&
|
(message.mid > lastReplyMarkup.mid || message.pFlags.is_outgoing) &&
|
||||||
message.message) {
|
(message as Message.message).message) {
|
||||||
lastReplyMarkup.pFlags.hidden = true;
|
lastReplyMarkup.pFlags.hidden = true;
|
||||||
// this.log('set', historyStorage.reply_markup)
|
// this.log('set', historyStorage.reply_markup)
|
||||||
return true;
|
return true;
|
||||||
@ -3079,10 +3090,10 @@ export class AppMessagesManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(message.action &&
|
assumeType<Message.messageService>(message);
|
||||||
message.action._ === 'messageActionChatDeleteUser' &&
|
if(message.action?._ === 'messageActionChatDeleteUser' &&
|
||||||
(lastReplyMarkup
|
(lastReplyMarkup
|
||||||
? message.action.user_id === lastReplyMarkup.fromId
|
? message.action.user_id === (lastReplyMarkup as ReplyMarkup.replyKeyboardMarkup).fromId
|
||||||
: appUsersManager.isBot(message.action.user_id)
|
: appUsersManager.isBot(message.action.user_id)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -4804,7 +4815,7 @@ export class AppMessagesManager {
|
|||||||
const wasTotalCount = historyStorage.history.length; */
|
const wasTotalCount = historyStorage.history.length; */
|
||||||
|
|
||||||
const mids = messages.map((message) => {
|
const mids = messages.map((message) => {
|
||||||
if(this.mergeReplyKeyboard(historyStorage, message)) {
|
if(this.mergeReplyKeyboard(historyStorage, message as MyMessage)) {
|
||||||
rootScope.dispatchEvent('history_reply_markup', {peerId});
|
rootScope.dispatchEvent('history_reply_markup', {peerId});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,8 +305,9 @@ export default class DialogsStorage {
|
|||||||
if(!message.pFlags.is_outgoing) {
|
if(!message.pFlags.is_outgoing) {
|
||||||
incomingMessage = message;
|
incomingMessage = message;
|
||||||
|
|
||||||
if(message.fromId !== dialog.peerId) {
|
const fromId = message.viaBotId || message.fromId;
|
||||||
this.appStateManager.requestPeer(message.fromId, 'topMessage_' + dialog.peerId, 1);
|
if(fromId !== dialog.peerId) {
|
||||||
|
this.appStateManager.requestPeer(fromId, 'topMessage_' + dialog.peerId, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -519,14 +520,17 @@ export default class DialogsStorage {
|
|||||||
const slice = historyStorage.history.slice;
|
const slice = historyStorage.history.slice;
|
||||||
/* if(historyStorage === undefined) { // warning
|
/* if(historyStorage === undefined) { // warning
|
||||||
historyStorage.history.push(mid);
|
historyStorage.history.push(mid);
|
||||||
if(this.mergeReplyKeyboard(historyStorage, message)) {
|
|
||||||
rootScope.broadcast('history_reply_markup', {peerId});
|
|
||||||
}
|
|
||||||
} else */if(!slice.length) {
|
} else */if(!slice.length) {
|
||||||
historyStorage.history.unshift(mid);
|
historyStorage.history.unshift(mid);
|
||||||
|
if(this.appMessagesManager.mergeReplyKeyboard(historyStorage, message)) {
|
||||||
|
rootScope.dispatchEvent('history_reply_markup', {peerId});
|
||||||
|
}
|
||||||
} else if(!slice.isEnd(SliceEnd.Bottom)) { // * this will probably never happen, however, if it does, then it will fix slice with top_message
|
} else if(!slice.isEnd(SliceEnd.Bottom)) { // * this will probably never happen, however, if it does, then it will fix slice with top_message
|
||||||
const slice = historyStorage.history.insertSlice([mid]);
|
const slice = historyStorage.history.insertSlice([mid]);
|
||||||
slice.setEnd(SliceEnd.Bottom);
|
slice.setEnd(SliceEnd.Bottom);
|
||||||
|
if(this.appMessagesManager.mergeReplyKeyboard(historyStorage, message)) {
|
||||||
|
rootScope.dispatchEvent('history_reply_markup', {peerId});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
historyStorage.maxId = mid;
|
historyStorage.maxId = mid;
|
||||||
|
@ -50,7 +50,8 @@
|
|||||||
{"name": "random_id", "type": "string"},
|
{"name": "random_id", "type": "string"},
|
||||||
{"name": "unread", "type": "true"},
|
{"name": "unread", "type": "true"},
|
||||||
{"name": "is_outgoing", "type": "true"},
|
{"name": "is_outgoing", "type": "true"},
|
||||||
{"name": "rReply", "type": "string"}
|
{"name": "rReply", "type": "string"},
|
||||||
|
{"name": "viaBotId", "type": "number"}
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
"predicate": "messageService",
|
"predicate": "messageService",
|
||||||
@ -61,7 +62,8 @@
|
|||||||
{"name": "fromId", "type": "number"},
|
{"name": "fromId", "type": "number"},
|
||||||
{"name": "unread", "type": "true"},
|
{"name": "unread", "type": "true"},
|
||||||
{"name": "is_outgoing", "type": "true"},
|
{"name": "is_outgoing", "type": "true"},
|
||||||
{"name": "rReply", "type": "string"}
|
{"name": "rReply", "type": "string"},
|
||||||
|
{"name": "viaBotId", "type": "number"}
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
"predicate": "messageEmpty",
|
"predicate": "messageEmpty",
|
||||||
@ -237,4 +239,23 @@
|
|||||||
"params": [
|
"params": [
|
||||||
{"name": "refreshTime", "type": "number"}
|
{"name": "refreshTime", "type": "number"}
|
||||||
]
|
]
|
||||||
|
}, {
|
||||||
|
"predicate": "replyKeyboardHide",
|
||||||
|
"params": [
|
||||||
|
{"name": "mid", "type": "number"}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
"predicate": "replyKeyboardForceReply",
|
||||||
|
"params": [
|
||||||
|
{"name": "mid", "type": "number"},
|
||||||
|
{"name": "hidden", "type": "true"},
|
||||||
|
{"name": "fromId", "type": "number"}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
"predicate": "replyKeyboardMarkup",
|
||||||
|
"params": [
|
||||||
|
{"name": "mid", "type": "number"},
|
||||||
|
{"name": "hidden", "type": "true"},
|
||||||
|
{"name": "fromId", "type": "number"}
|
||||||
|
]
|
||||||
}]
|
}]
|
@ -177,15 +177,8 @@ $chat-helper-size: 39px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-scheduled {
|
.btn-scheduled {
|
||||||
position: absolute;
|
/* position: absolute;
|
||||||
right: 3.625rem;
|
right: 3.625rem; */
|
||||||
align-self: center;
|
|
||||||
display: none !important;
|
|
||||||
margin: 0 !important;
|
|
||||||
|
|
||||||
@include animation-level(2) {
|
|
||||||
animation: grow-icon .4s forwards ease-in-out !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
content: "";
|
content: "";
|
||||||
@ -199,8 +192,18 @@ $chat-helper-size: 39px;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.float {
|
||||||
|
align-self: center;
|
||||||
|
display: none !important;
|
||||||
|
margin: 0 .75rem 0 0 !important;
|
||||||
|
|
||||||
|
@include animation-level(2) {
|
||||||
|
animation: grow-icon .4s forwards ease-in-out !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:not(.is-recording) {
|
&:not(.is-recording) {
|
||||||
.btn-scheduled.show:not(.hide) {
|
.float.show:not(.hide) {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1261,6 +1261,12 @@ $bubble-margin: .25rem;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.with-reply-markup {
|
||||||
|
.bubble-content {
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.with-replies .attachment {
|
&.with-replies .attachment {
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
|
64
src/scss/partials/_replyKeyboard.scss
Normal file
64
src/scss/partials/_replyKeyboard.scss
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
.reply-keyboard {
|
||||||
|
background: var(--surface-color);
|
||||||
|
position: absolute !important;
|
||||||
|
right: 0;
|
||||||
|
bottom: calc(100% + .625rem);
|
||||||
|
width: 26.25rem !important;
|
||||||
|
//height: 26.25rem;
|
||||||
|
max-height: 26.25rem;
|
||||||
|
box-shadow: 0px 5px 10px 5px rgba(16, 35, 47, .14);
|
||||||
|
z-index: 3;
|
||||||
|
border-radius: $border-radius-medium;
|
||||||
|
transition: transform var(--esg-transition), opacity var(--esg-transition);
|
||||||
|
transform: scale(0);
|
||||||
|
opacity: 0;
|
||||||
|
transform-origin: bottom right;
|
||||||
|
padding: .625rem !important;
|
||||||
|
display: block !important;
|
||||||
|
|
||||||
|
@include respond-to(esg-bottom-new) {
|
||||||
|
bottom: calc(100% + .5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.animation-level-0 & {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-row {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
& + & {
|
||||||
|
margin-top: .3125rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-button {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: .375rem;
|
||||||
|
border: 2px solid var(--primary-color);
|
||||||
|
text-align: center;
|
||||||
|
color: var(--primary-color);
|
||||||
|
background-color: transparent;
|
||||||
|
height: 3rem;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: .9375rem;
|
||||||
|
|
||||||
|
@include animation-level(2) {
|
||||||
|
transition: color .15s, background-color .15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include hover() {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
& + & {
|
||||||
|
margin-left: .3125rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -262,6 +262,7 @@ html.night {
|
|||||||
@import "partials/transition";
|
@import "partials/transition";
|
||||||
@import "partials/row";
|
@import "partials/row";
|
||||||
@import "partials/colorPicker";
|
@import "partials/colorPicker";
|
||||||
|
@import "partials/replyKeyboard";
|
||||||
|
|
||||||
@import "partials/popups/popup";
|
@import "partials/popups/popup";
|
||||||
@import "partials/popups/editAvatar";
|
@import "partials/popups/editAvatar";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user