Forward options
Fixed opening scheduled chat after forwarding
This commit is contained in:
parent
69012a40b2
commit
31fcc95989
@ -16,10 +16,12 @@ export type ButtonMenuItemOptions = {
|
||||
icon?: string,
|
||||
text?: LangPackKey,
|
||||
regularText?: string,
|
||||
onClick: (e: MouseEvent | TouchEvent) => void,
|
||||
onClick: (e: MouseEvent | TouchEvent) => void | boolean,
|
||||
element?: HTMLElement,
|
||||
textElement?: HTMLElement,
|
||||
options?: AttachClickOptions,
|
||||
checkboxField?: CheckboxField,
|
||||
noCheckboxClickListener?: boolean,
|
||||
keepOpen?: boolean
|
||||
/* , cancelEvent?: true */
|
||||
};
|
||||
@ -27,34 +29,43 @@ export type ButtonMenuItemOptions = {
|
||||
const ButtonMenuItem = (options: ButtonMenuItemOptions) => {
|
||||
if(options.element) return options.element;
|
||||
|
||||
const {icon, text, onClick} = options;
|
||||
const {icon, text, onClick, checkboxField, noCheckboxClickListener} = options;
|
||||
const el = document.createElement('div');
|
||||
el.className = 'btn-menu-item' + (icon ? ' tgico-' + icon : '');
|
||||
ripple(el);
|
||||
|
||||
const t = text ? i18n(text) : document.createElement('span');
|
||||
if(options.regularText) t.innerHTML = options.regularText;
|
||||
t.classList.add('btn-menu-item-text');
|
||||
el.append(t);
|
||||
|
||||
if(options.checkboxField) {
|
||||
el.append(options.checkboxField.label);
|
||||
attachClickEvent(el, () => {
|
||||
options.checkboxField.checked = !options.checkboxField.checked;
|
||||
}, options.options);
|
||||
let textElement = options.textElement;
|
||||
if(!textElement) {
|
||||
textElement = options.textElement = text ? i18n(text) : document.createElement('span');
|
||||
if(options.regularText) textElement.innerHTML = options.regularText;
|
||||
}
|
||||
|
||||
const keepOpen = !!options.checkboxField || !!options.keepOpen;
|
||||
textElement.classList.add('btn-menu-item-text');
|
||||
el.append(textElement);
|
||||
|
||||
const keepOpen = !!checkboxField || !!options.keepOpen;
|
||||
|
||||
// * cancel mobile keyboard close
|
||||
attachClickEvent(el, CLICK_EVENT_NAME !== 'click' || keepOpen ? (e) => {
|
||||
attachClickEvent(el, /* CLICK_EVENT_NAME !== 'click' || keepOpen ? */ (e) => {
|
||||
cancelEvent(e);
|
||||
onClick(e);
|
||||
const result = onClick(e);
|
||||
|
||||
if(result === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!keepOpen) {
|
||||
closeBtnMenu();
|
||||
}
|
||||
} : onClick, options.options);
|
||||
|
||||
if(checkboxField && !noCheckboxClickListener/* && result !== false */) {
|
||||
checkboxField.checked = checkboxField.input.type === 'radio' ? true : !checkboxField.checked;
|
||||
}
|
||||
}/* : onClick */, options.options);
|
||||
|
||||
if(checkboxField) {
|
||||
el.append(checkboxField.label);
|
||||
}
|
||||
|
||||
return options.element = el;
|
||||
};
|
||||
|
@ -1854,12 +1854,18 @@ export default class ChatBubbles {
|
||||
return {cached: true, promise: this.chat.setPeerPromise};
|
||||
} */
|
||||
|
||||
const chatType = this.chat.type;
|
||||
|
||||
if(chatType === 'scheduled') {
|
||||
lastMsgId = 0;
|
||||
}
|
||||
|
||||
this.historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);
|
||||
let topMessage = this.chat.type === 'pinned' ? this.appMessagesManager.pinnedMessages[peerId].maxId : this.historyStorage.maxId ?? 0;
|
||||
let topMessage = chatType === 'pinned' ? this.appMessagesManager.pinnedMessages[peerId].maxId : this.historyStorage.maxId ?? 0;
|
||||
const isTarget = lastMsgId !== undefined;
|
||||
|
||||
// * this one will fix topMessage for null message in history (e.g. channel comments with only 1 comment and it is a topMessage)
|
||||
/* if(this.chat.type !== 'pinned' && topMessage && !historyStorage.history.slice.includes(topMessage)) {
|
||||
/* if(chatType !== 'pinned' && topMessage && !historyStorage.history.slice.includes(topMessage)) {
|
||||
topMessage = 0;
|
||||
} */
|
||||
|
||||
@ -1884,6 +1890,8 @@ export default class ChatBubbles {
|
||||
|
||||
const isJump = lastMsgId !== topMessage;
|
||||
|
||||
const {scrollable} = this;
|
||||
|
||||
if(samePeer) {
|
||||
const mounted = this.getMountedBubble(lastMsgId);
|
||||
if(mounted) {
|
||||
@ -1893,7 +1901,7 @@ export default class ChatBubbles {
|
||||
this.chat.dispatchEvent('setPeer', lastMsgId, false);
|
||||
} else if(topMessage && !isJump) {
|
||||
//this.log('will scroll down', this.scroll.scrollTop, this.scroll.scrollHeight);
|
||||
this.scrollable.scrollTop = this.scrollable.scrollHeight;
|
||||
scrollable.scrollTop = scrollable.scrollHeight;
|
||||
this.chat.dispatchEvent('setPeer', lastMsgId, true);
|
||||
}
|
||||
|
||||
@ -1909,16 +1917,16 @@ export default class ChatBubbles {
|
||||
this.replyFollowHistory.length = 0;
|
||||
|
||||
this.passEntities = {
|
||||
messageEntityBotCommand: this.appPeersManager.isAnyGroup(this.peerId) || this.appUsersManager.isBot(this.peerId)
|
||||
messageEntityBotCommand: this.appPeersManager.isAnyGroup(peerId) || this.appUsersManager.isBot(peerId)
|
||||
};
|
||||
}
|
||||
|
||||
if(DEBUG) {
|
||||
this.log('setPeer peerId:', this.peerId, this.historyStorage, lastMsgId, topMessage);
|
||||
this.log('setPeer peerId:', peerId, this.historyStorage, lastMsgId, topMessage);
|
||||
}
|
||||
|
||||
// add last message, bc in getHistory will load < max_id
|
||||
const additionMsgId = isJump || this.chat.type === 'scheduled' ? 0 : topMessage;
|
||||
const additionMsgId = isJump || chatType === 'scheduled' ? 0 : topMessage;
|
||||
|
||||
/* this.setPeerPromise = null;
|
||||
this.preloader.detach();
|
||||
@ -1943,12 +1951,12 @@ export default class ChatBubbles {
|
||||
|
||||
const oldChatInner = this.chatInner;
|
||||
this.cleanup();
|
||||
this.chatInner = document.createElement('div');
|
||||
const chatInner = this.chatInner = document.createElement('div');
|
||||
if(samePeer) {
|
||||
this.chatInner.className = oldChatInner.className;
|
||||
this.chatInner.classList.remove('disable-hover', 'is-scrolling');
|
||||
chatInner.className = oldChatInner.className;
|
||||
chatInner.classList.remove('disable-hover', 'is-scrolling');
|
||||
} else {
|
||||
this.chatInner.classList.add('bubbles-inner');
|
||||
chatInner.classList.add('bubbles-inner');
|
||||
}
|
||||
|
||||
this.lazyLoadQueue.lock();
|
||||
@ -1970,7 +1978,7 @@ export default class ChatBubbles {
|
||||
// clear
|
||||
if(!cached) {
|
||||
if(!samePeer) {
|
||||
this.scrollable.container.textContent = '';
|
||||
scrollable.container.textContent = '';
|
||||
//oldChatInner.remove();
|
||||
this.chat.finishPeerChange(isTarget, isJump, lastMsgId);
|
||||
this.preloader.attach(this.bubblesContainer);
|
||||
@ -2000,9 +2008,9 @@ export default class ChatBubbles {
|
||||
|
||||
// this.ladderDeferred.resolve();
|
||||
|
||||
this.scrollable.lastScrollDirection = 0;
|
||||
this.scrollable.lastScrollTop = 0;
|
||||
replaceContent(this.scrollable.container, this.chatInner);
|
||||
scrollable.lastScrollDirection = 0;
|
||||
scrollable.lastScrollTop = 0;
|
||||
replaceContent(scrollable.container, chatInner);
|
||||
|
||||
animationIntersector.unlockGroup(CHAT_ANIMATION_GROUP);
|
||||
animationIntersector.checkAnimations(false, CHAT_ANIMATION_GROUP/* , true */);
|
||||
@ -2013,7 +2021,7 @@ export default class ChatBubbles {
|
||||
|
||||
//if(dialog && lastMsgID && lastMsgID !== topMessage && (this.bubbles[lastMsgID] || this.firstUnreadBubble)) {
|
||||
if(savedPosition) {
|
||||
this.scrollable.scrollTop = savedPosition.top;
|
||||
scrollable.scrollTop = savedPosition.top;
|
||||
/* const mountedByLastMsgId = this.getMountedBubble(lastMsgId);
|
||||
let bubble: HTMLElement = mountedByLastMsgId?.bubble;
|
||||
if(!bubble?.parentElement) {
|
||||
@ -2023,15 +2031,15 @@ export default class ChatBubbles {
|
||||
if(bubble) {
|
||||
const top = bubble.getBoundingClientRect().top;
|
||||
const distance = savedPosition.top - top;
|
||||
this.scrollable.scrollTop += distance;
|
||||
scrollable.scrollTop += distance;
|
||||
} */
|
||||
} else if((topMessage && isJump) || isTarget) {
|
||||
const fromUp = maxBubbleId > 0 && (maxBubbleId < lastMsgId || lastMsgId < 0);
|
||||
const followingUnread = readMaxId === lastMsgId && !isTarget;
|
||||
if(!fromUp && samePeer) {
|
||||
this.scrollable.scrollTop = 99999;
|
||||
scrollable.scrollTop = 99999;
|
||||
} else if(fromUp/* && (samePeer || forwardingUnread) */) {
|
||||
this.scrollable.scrollTop = 0;
|
||||
scrollable.scrollTop = 0;
|
||||
}
|
||||
|
||||
const mountedByLastMsgId = this.getMountedBubble(lastMsgId);
|
||||
@ -2048,7 +2056,7 @@ export default class ChatBubbles {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.scrollable.scrollTop = 99999;
|
||||
scrollable.scrollTop = 99999;
|
||||
}
|
||||
|
||||
this.onScroll();
|
||||
@ -2056,7 +2064,7 @@ export default class ChatBubbles {
|
||||
const middleware = this.getMiddleware();
|
||||
const afterSetPromise = Promise.all([setPeerPromise, getHeavyAnimationPromise()]);
|
||||
afterSetPromise.then(() => { // check whether list isn't full
|
||||
this.scrollable.checkForTriggers();
|
||||
scrollable.checkForTriggers();
|
||||
});
|
||||
|
||||
this.chat.dispatchEvent('setPeer', lastMsgId, !isJump);
|
||||
@ -2074,7 +2082,7 @@ export default class ChatBubbles {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scrollable.checkForTriggers();
|
||||
scrollable.checkForTriggers();
|
||||
|
||||
if(needFetchInterval) {
|
||||
const f = () => {
|
||||
@ -2092,7 +2100,7 @@ export default class ChatBubbles {
|
||||
|
||||
const slice = historyStorage.history.slice;
|
||||
const isBottomEnd = slice.isEnd(SliceEnd.Bottom);
|
||||
if(this.scrollable.loadedAll.bottom && this.scrollable.loadedAll.bottom !== isBottomEnd) {
|
||||
if(scrollable.loadedAll.bottom && scrollable.loadedAll.bottom !== isBottomEnd) {
|
||||
this.setLoaded('bottom', isBottomEnd);
|
||||
this.onScroll();
|
||||
}
|
||||
@ -2114,14 +2122,14 @@ export default class ChatBubbles {
|
||||
});
|
||||
}
|
||||
|
||||
this.log('scrolledAllDown:', this.scrollable.loadedAll.bottom);
|
||||
this.log('scrolledAllDown:', scrollable.loadedAll.bottom);
|
||||
|
||||
//if(!this.unreaded.length && dialog) { // lol
|
||||
if(this.scrollable.loadedAll.bottom && topMessage && !this.unreaded.size) { // lol
|
||||
if(scrollable.loadedAll.bottom && topMessage && !this.unreaded.size) { // lol
|
||||
this.onScrolledAllDown();
|
||||
}
|
||||
|
||||
if(this.chat.type === 'chat') {
|
||||
if(chatType === 'chat') {
|
||||
const dialog = this.appMessagesManager.getDialogOnly(peerId);
|
||||
if(dialog?.pFlags.unread_mark) {
|
||||
this.appMessagesManager.markDialogUnread(peerId, true);
|
||||
@ -2624,7 +2632,7 @@ export default class ChatBubbles {
|
||||
if(message.pFlags.unread || isOutgoing) this.unreadOut.add(message.mid);
|
||||
let status = '';
|
||||
if(isOutgoing) status = 'is-sending';
|
||||
else status = message.pFlags.unread ? 'is-sent' : 'is-read';
|
||||
else status = message.pFlags.unread || message.pFlags.is_scheduled ? 'is-sent' : 'is-read';
|
||||
bubble.classList.add(status);
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ import ReplyKeyboard from './replyKeyboard';
|
||||
import InlineHelper from './inlineHelper';
|
||||
import debounce from '../../helpers/schedulers/debounce';
|
||||
import noop from '../../helpers/noop';
|
||||
import { putPreloader } from '../misc';
|
||||
import { openBtnMenu, putPreloader } from '../misc';
|
||||
import SetTransition from '../singleTransition';
|
||||
import PeerTitle from '../peerTitle';
|
||||
import { fastRaf } from '../../helpers/schedulers';
|
||||
@ -84,6 +84,10 @@ import { NULL_PEER_ID } from '../../lib/mtproto/mtproto_config';
|
||||
import setCaretAt from '../../helpers/dom/setCaretAt';
|
||||
import getKeyFromEvent from '../../helpers/dom/getKeyFromEvent';
|
||||
import getKeyFromEventCaseInsensitive from '../../helpers/dom/getKeyFromEventCaseInsensitive';
|
||||
import CheckboxField from '../checkboxField';
|
||||
import DropdownHover from '../../helpers/dropdownHover';
|
||||
import RadioForm from '../radioForm';
|
||||
import findUpTag from '../../helpers/dom/findUpTag';
|
||||
|
||||
const RECORD_MIN_TIME = 500;
|
||||
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
||||
@ -123,7 +127,17 @@ export default class ChatInput {
|
||||
iconBtn: HTMLButtonElement
|
||||
} = {} as any;
|
||||
|
||||
private forwardElements: {} = {} as any;
|
||||
private forwardElements: {
|
||||
changePeer: ButtonMenuItemOptions,
|
||||
showSender: ButtonMenuItemOptions,
|
||||
hideSender: ButtonMenuItemOptions,
|
||||
showCaption: ButtonMenuItemOptions,
|
||||
hideCaption: ButtonMenuItemOptions,
|
||||
container: HTMLElement,
|
||||
modifyArgs?: ButtonMenuItemOptions[]
|
||||
} = {} as any;
|
||||
private forwardHover: DropdownHover;
|
||||
private forwardWasDroppingAuthor: boolean;
|
||||
|
||||
private getWebPagePromise: Promise<void>;
|
||||
private willSendWebPage: WebPage = null;
|
||||
@ -313,14 +327,119 @@ export default class ChatInput {
|
||||
|
||||
this.replyElements.container.append(this.replyElements.iconBtn, this.replyElements.cancelBtn);
|
||||
|
||||
const forwardBtnMenu = ButtonMenu([], this.listenerSetter);
|
||||
//
|
||||
|
||||
this.forwardElements = {
|
||||
container: forwardBtnMenu
|
||||
} as any;
|
||||
const onHideAuthorClick = () => {
|
||||
isChangingAuthor = true;
|
||||
return this.canToggleHideAuthor();
|
||||
};
|
||||
|
||||
const onHideCaptionClick = () => {
|
||||
isChangingAuthor = false;
|
||||
};
|
||||
|
||||
const forwardElements: ChatInput['forwardElements'] = this.forwardElements = {} as any;
|
||||
let isChangingAuthor = false;
|
||||
const forwardButtons: ButtonMenuItemOptions[] = [
|
||||
forwardElements.showSender = {
|
||||
text: 'Chat.Alert.Forward.Action.Show1',
|
||||
onClick: onHideAuthorClick,
|
||||
checkboxField: new CheckboxField({checked: true})
|
||||
},
|
||||
forwardElements.hideSender = {
|
||||
text: 'Chat.Alert.Forward.Action.Hide1',
|
||||
onClick: onHideAuthorClick,
|
||||
checkboxField: new CheckboxField({checked: false})
|
||||
},
|
||||
forwardElements.showCaption = {
|
||||
text: 'Chat.Alert.Forward.Action.ShowCaption',
|
||||
onClick: onHideCaptionClick,
|
||||
checkboxField: new CheckboxField({checked: true})
|
||||
},
|
||||
forwardElements.hideCaption = {
|
||||
text: 'Chat.Alert.Forward.Action.HideCaption',
|
||||
onClick: onHideCaptionClick,
|
||||
checkboxField: new CheckboxField({checked: false})
|
||||
},
|
||||
forwardElements.changePeer = {
|
||||
text: 'Chat.Alert.Forward.Action.Another',
|
||||
onClick: () => {
|
||||
this.changeForwardRecipient();
|
||||
},
|
||||
icon: 'replace'
|
||||
}
|
||||
];
|
||||
const forwardBtnMenu = forwardElements.container = ButtonMenu(forwardButtons, this.listenerSetter);
|
||||
// forwardBtnMenu.classList.add('top-center');
|
||||
|
||||
const children = Array.from(forwardBtnMenu.children) as HTMLElement[];
|
||||
const groups: {
|
||||
elements: HTMLElement[],
|
||||
onChange: (value: string, event: Event) => void
|
||||
}[] = [{
|
||||
elements: children.slice(0, 2),
|
||||
onChange: (value, e) => {
|
||||
const checked = !!+value;
|
||||
if(isChangingAuthor) {
|
||||
this.forwardWasDroppingAuthor = !checked;
|
||||
}
|
||||
|
||||
const replyTitle = this.replyElements.container.querySelector('.reply-title');
|
||||
if(replyTitle) {
|
||||
const el = replyTitle.firstElementChild as HTMLElement;
|
||||
const i = I18n.weakMap.get(el) as I18n.IntlElement;
|
||||
const langPackKey: LangPackKey = forwardElements.showSender.checkboxField.checked ? 'Chat.Accessory.Forward' : 'Chat.Accessory.Hidden';
|
||||
i.key = langPackKey;
|
||||
i.update();
|
||||
}
|
||||
}
|
||||
}, {
|
||||
elements: children.slice(2, 4),
|
||||
onChange: (value) => {
|
||||
const checked = !!+value;
|
||||
let b: ButtonMenuItemOptions;
|
||||
if(checked && this.forwardWasDroppingAuthor !== undefined) {
|
||||
b = this.forwardWasDroppingAuthor ? forwardElements.hideSender : forwardElements.showSender;
|
||||
} else {
|
||||
b = checked ? forwardElements.showSender : forwardElements.hideSender;
|
||||
}
|
||||
|
||||
b.checkboxField.checked = true;
|
||||
}
|
||||
}];
|
||||
groups.forEach(group => {
|
||||
const container = RadioForm(group.elements.map(e => {
|
||||
return {
|
||||
container: e,
|
||||
input: e.querySelector('input')
|
||||
};
|
||||
}), group.onChange);
|
||||
|
||||
const hr = document.createElement('hr');
|
||||
container.append(hr);
|
||||
forwardBtnMenu.append(container);
|
||||
});
|
||||
|
||||
forwardBtnMenu.append(forwardElements.changePeer.element);
|
||||
|
||||
if(!IS_TOUCH_SUPPORTED) {
|
||||
const forwardHover = this.forwardHover = new DropdownHover({
|
||||
element: forwardBtnMenu
|
||||
});
|
||||
}
|
||||
|
||||
forwardElements.modifyArgs = forwardButtons.slice(0, -1);
|
||||
this.replyElements.container.append(forwardBtnMenu);
|
||||
|
||||
forwardElements.modifyArgs.forEach((b, idx) => {
|
||||
const {input} = b.checkboxField;
|
||||
input.type = 'radio';
|
||||
input.name = idx < 2 ? 'author' : 'caption';
|
||||
input.value = '' + +!(idx % 2);
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
this.newMessageWrapper = document.createElement('div');
|
||||
this.newMessageWrapper.classList.add('new-message-wrapper');
|
||||
|
||||
@ -467,7 +586,7 @@ export default class ChatInput {
|
||||
openSide: 'top-left',
|
||||
onContextElement: this.btnSend,
|
||||
onOpen: () => {
|
||||
return !this.isInputEmpty();
|
||||
return !this.isInputEmpty() || !!Object.keys(this.forwarding).length;
|
||||
}
|
||||
});
|
||||
|
||||
@ -706,9 +825,15 @@ export default class ChatInput {
|
||||
}
|
||||
|
||||
public scheduleSending = (callback: () => void = this.sendMessage.bind(this, true), initDate = new Date()) => {
|
||||
const canSendWhenOnline = rootScope.myId !== this.chat.peerId && this.chat.peerId.isUser() && this.appUsersManager.isUserOnlineVisible(this.chat.peerId);
|
||||
const {peerId} = this.chat;
|
||||
const middleware = this.chat.bubbles.getMiddleware();
|
||||
const canSendWhenOnline = rootScope.myId !== peerId && peerId.isUser() && this.appUsersManager.isUserOnlineVisible(peerId);
|
||||
|
||||
new PopupSchedule(initDate, (timestamp) => {
|
||||
if(!middleware()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const minTimestamp = (Date.now() / 1000 | 0) + 10;
|
||||
if(timestamp <= minTimestamp) {
|
||||
timestamp = undefined;
|
||||
@ -718,7 +843,13 @@ export default class ChatInput {
|
||||
callback();
|
||||
|
||||
if(this.chat.type !== 'scheduled' && timestamp) {
|
||||
this.appImManager.openScheduled(this.chat.peerId);
|
||||
setTimeout(() => { // ! need timeout here because .forwardMessages will be called after timeout
|
||||
if(!middleware()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.appImManager.openScheduled(peerId);
|
||||
}, 0);
|
||||
}
|
||||
}, canSendWhenOnline).show();
|
||||
};
|
||||
@ -842,6 +973,12 @@ export default class ChatInput {
|
||||
}/* else if(this.chat.type === 'chat') {
|
||||
} */
|
||||
|
||||
if(this.forwardElements) {
|
||||
this.forwardWasDroppingAuthor = false;
|
||||
this.forwardElements.showCaption.checkboxField.setValueSilently(true);
|
||||
this.forwardElements.showSender.checkboxField.setValueSilently(true);
|
||||
}
|
||||
|
||||
if(this.btnScheduled) {
|
||||
this.btnScheduled.classList.add('hide');
|
||||
const middleware = this.chat.bubbles.getMiddleware();
|
||||
@ -1668,8 +1805,19 @@ export default class ChatInput {
|
||||
private onHelperClick = (e: Event) => {
|
||||
cancelEvent(e);
|
||||
|
||||
if(!findUpClassName(e.target, 'reply-wrapper')) return;
|
||||
if(!findUpClassName(e.target, 'reply')) return;
|
||||
if(this.helperType === 'forward') {
|
||||
if(IS_TOUCH_SUPPORTED && !this.forwardElements.container.classList.contains('active')) {
|
||||
openBtnMenu(this.forwardElements.container);
|
||||
}
|
||||
} else if(this.helperType === 'reply') {
|
||||
this.chat.setMessageId(this.replyToMsgId);
|
||||
} else if(this.helperType === 'edit') {
|
||||
this.chat.setMessageId(this.editMsgId);
|
||||
}
|
||||
};
|
||||
|
||||
private changeForwardRecipient() {
|
||||
if(this.helperWaitingForward) return;
|
||||
this.helperWaitingForward = true;
|
||||
|
||||
@ -1688,12 +1836,7 @@ export default class ChatInput {
|
||||
helperFunc();
|
||||
}
|
||||
});
|
||||
} else if(this.helperType === 'reply') {
|
||||
this.chat.setMessageId(this.replyToMsgId);
|
||||
} else if(this.helperType === 'edit') {
|
||||
this.chat.setMessageId(this.editMsgId);
|
||||
}
|
||||
};
|
||||
|
||||
public clearInput(canSetDraft = true, fireEvent = true, clearValue = '') {
|
||||
if(document.activeElement === this.messageInput && IS_MOBILE_SAFARI) { // fix first char uppercase
|
||||
@ -1787,37 +1930,41 @@ export default class ChatInput {
|
||||
}
|
||||
|
||||
public sendMessage(force = false) {
|
||||
if(this.chat.type === 'scheduled' && !force && !this.editMsgId) {
|
||||
const {editMsgId, chat} = this;
|
||||
if(chat.type === 'scheduled' && !force && !editMsgId) {
|
||||
this.scheduleSending();
|
||||
return;
|
||||
}
|
||||
|
||||
const {threadId, peerId} = chat;
|
||||
const {replyToMsgId, noWebPage, sendSilent, scheduleDate} = this;
|
||||
|
||||
const {value, entities} = getRichValue(this.messageInputField.input);
|
||||
|
||||
//return;
|
||||
if(this.editMsgId) {
|
||||
if(editMsgId) {
|
||||
const message = this.editMessage;
|
||||
if(!!value.trim() || message.media) {
|
||||
if(value.trim() || message.media) {
|
||||
this.appMessagesManager.editMessage(message, value, {
|
||||
entities,
|
||||
noWebPage: this.noWebPage
|
||||
noWebPage: noWebPage
|
||||
});
|
||||
|
||||
this.onMessageSent();
|
||||
} else {
|
||||
new PopupDeleteMessages(this.chat.peerId, [this.editMsgId], this.chat.type);
|
||||
new PopupDeleteMessages(peerId, [editMsgId], chat.type);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.appMessagesManager.sendText(this.chat.peerId, value, {
|
||||
} else if(value.trim()) {
|
||||
this.appMessagesManager.sendText(peerId, value, {
|
||||
entities,
|
||||
replyToMsgId: this.replyToMsgId,
|
||||
threadId: this.chat.threadId,
|
||||
noWebPage: this.noWebPage,
|
||||
replyToMsgId: replyToMsgId,
|
||||
threadId: threadId,
|
||||
noWebPage: noWebPage,
|
||||
webPage: this.getWebPagePromise ? undefined : this.willSendWebPage,
|
||||
scheduleDate: this.scheduleDate,
|
||||
silent: this.sendSilent,
|
||||
scheduleDate: scheduleDate,
|
||||
silent: sendSilent,
|
||||
clearDraft: true
|
||||
});
|
||||
|
||||
@ -1828,14 +1975,13 @@ export default class ChatInput {
|
||||
// * wait for sendText set messageId for invokeAfterMsg
|
||||
if(this.forwarding) {
|
||||
const forwarding = copy(this.forwarding);
|
||||
const peerId = this.chat.peerId;
|
||||
const silent = this.sendSilent;
|
||||
const scheduleDate = this.scheduleDate;
|
||||
setTimeout(() => {
|
||||
for(const fromPeerId in forwarding) {
|
||||
this.appMessagesManager.forwardMessages(peerId, fromPeerId.toPeerId(), forwarding[fromPeerId], {
|
||||
silent,
|
||||
scheduleDate: scheduleDate
|
||||
silent: sendSilent,
|
||||
scheduleDate: scheduleDate,
|
||||
dropAuthor: this.forwardElements.hideSender.checkboxField.checked,
|
||||
dropCaptions: this.forwardElements.hideCaption.checkboxField.checked
|
||||
});
|
||||
}
|
||||
|
||||
@ -1883,6 +2029,12 @@ export default class ChatInput {
|
||||
return false;
|
||||
}
|
||||
|
||||
private canToggleHideAuthor() {
|
||||
const hideCaptionCheckboxField = this.forwardElements.hideCaption.checkboxField;
|
||||
return !hideCaptionCheckboxField.checked ||
|
||||
findUpTag(hideCaptionCheckboxField.label, 'FORM').classList.contains('hide');
|
||||
}
|
||||
|
||||
/* public sendSomething(callback: () => void, force = false) {
|
||||
if(this.chat.type === 'scheduled' && !force) {
|
||||
this.scheduleSending(() => this.sendSomething(callback, true));
|
||||
@ -1915,7 +2067,7 @@ export default class ChatInput {
|
||||
//const peerTitles: string[]
|
||||
const fromPeerIds = Object.keys(fromPeerIdsMids).map(fromPeerId => fromPeerId.toPeerId());
|
||||
const smth: Set<string> = new Set();
|
||||
let length = 0;
|
||||
let length = 0, messagesWithCaptionsLength = 0;
|
||||
|
||||
fromPeerIds.forEach(fromPeerId => {
|
||||
const mids = fromPeerIdsMids[fromPeerId];
|
||||
@ -1926,6 +2078,10 @@ export default class ChatInput {
|
||||
} else {
|
||||
smth.add('P' + message.fromId);
|
||||
}
|
||||
|
||||
if(message.media && message.message) {
|
||||
++messagesWithCaptionsLength;
|
||||
}
|
||||
});
|
||||
|
||||
length += mids.length;
|
||||
@ -1935,19 +2091,25 @@ export default class ChatInput {
|
||||
const peerTitles = [...smth].map(smth => {
|
||||
const type = smth[0];
|
||||
smth = smth.slice(1);
|
||||
return type === 'P' ?
|
||||
new PeerTitle({peerId: smth.toPeerId(), dialog: false, onlyFirstName}).element :
|
||||
(onlyFirstName ? smth.split(' ')[0] : smth);
|
||||
if(type === 'P') {
|
||||
const peerId = smth.toPeerId();
|
||||
return peerId === rootScope.myId ? i18n('Chat.Accessory.Forward.You') : new PeerTitle({peerId, dialog: false, onlyFirstName}).element;
|
||||
} else {
|
||||
return onlyFirstName ? smth.split(' ')[0] : smth;
|
||||
}
|
||||
});
|
||||
|
||||
const title = document.createDocumentFragment();
|
||||
const titleKey: LangPackKey = this.forwardElements.showSender.checkboxField.checked ? 'Chat.Accessory.Forward' : 'Chat.Accessory.Hidden';
|
||||
const title = i18n(titleKey, [length]);
|
||||
|
||||
const senderTitles = document.createDocumentFragment();
|
||||
if(peerTitles.length < 3) {
|
||||
title.append(...join(peerTitles, false));
|
||||
senderTitles.append(...join(peerTitles, false));
|
||||
} else {
|
||||
title.append(peerTitles[0], i18n('AndOther', [peerTitles.length - 1]));
|
||||
senderTitles.append(peerTitles[0], i18n('AndOther', [peerTitles.length - 1]));
|
||||
}
|
||||
|
||||
let firstMessage: any, usingFullAlbum: boolean;
|
||||
let firstMessage: Message.message, usingFullAlbum: boolean;
|
||||
if(fromPeerIds.length === 1) {
|
||||
const fromPeerId = fromPeerIds[0];
|
||||
const mids = fromPeerIdsMids[fromPeerId];
|
||||
@ -1962,12 +2124,44 @@ export default class ChatInput {
|
||||
}
|
||||
}
|
||||
|
||||
const subtitleFragment = document.createDocumentFragment();
|
||||
const delimiter = ': ';
|
||||
if(usingFullAlbum || length === 1) {
|
||||
const mids = fromPeerIdsMids[fromPeerIds[0]];
|
||||
const replyFragment = this.appMessagesManager.wrapMessageForReply(firstMessage, undefined, mids);
|
||||
this.setTopInfo('forward', f, title, replyFragment);
|
||||
subtitleFragment.append(
|
||||
senderTitles,
|
||||
delimiter,
|
||||
replyFragment
|
||||
);
|
||||
} else {
|
||||
this.setTopInfo('forward', f, title, i18n('ForwardedMessageCount', [length]));
|
||||
subtitleFragment.append(
|
||||
i18n('Chat.Accessory.Forward.From'),
|
||||
delimiter,
|
||||
senderTitles
|
||||
);
|
||||
}
|
||||
|
||||
let newReply = this.setTopInfo('forward', f, title, subtitleFragment);
|
||||
|
||||
this.forwardElements.modifyArgs.forEach((b, idx) => {
|
||||
const text = b.textElement;
|
||||
const intl: I18n.IntlElement = I18n.weakMap.get(text) as any;
|
||||
intl.args = [idx < 2 ? fromPeerIds.length : messagesWithCaptionsLength];
|
||||
intl.update();
|
||||
});
|
||||
|
||||
const form = findUpTag(this.forwardElements.showCaption.checkboxField.label, 'FORM');
|
||||
form.classList.toggle('hide', !messagesWithCaptionsLength);
|
||||
const hideCaption = this.forwardElements.hideCaption.checkboxField.checked;
|
||||
if(messagesWithCaptionsLength && hideCaption) {
|
||||
this.forwardElements.hideSender.checkboxField.setValueSilently(true);
|
||||
} else if(this.forwardWasDroppingAuthor !== undefined) {
|
||||
(this.forwardWasDroppingAuthor ? this.forwardElements.hideSender : this.forwardElements.showSender).checkboxField.setValueSilently(true);
|
||||
}
|
||||
|
||||
if(this.forwardHover) {
|
||||
this.forwardHover.attachButtonListener(newReply, this.listenerSetter);
|
||||
}
|
||||
|
||||
this.forwarding = fromPeerIdsMids;
|
||||
@ -2114,6 +2308,8 @@ export default class ChatInput {
|
||||
setTimeout(() => {
|
||||
this.updateSendBtn();
|
||||
}, 0);
|
||||
|
||||
return newReply;
|
||||
}
|
||||
|
||||
// public saveScroll() {
|
||||
|
@ -44,7 +44,7 @@ export function wrapReplyDivAndCaption(options: {
|
||||
let middleware: () => boolean;
|
||||
if(media && mediaEl) {
|
||||
subtitleEl.textContent = '';
|
||||
subtitleEl.append(appMessagesManager.wrapMessageForReply(message));
|
||||
subtitleEl.append(appMessagesManager.wrapMessageForReply(message, undefined, undefined, undefined, undefined, true));
|
||||
|
||||
//console.log('wrap reply', media);
|
||||
|
||||
|
@ -622,7 +622,7 @@ export class SearchSelection extends AppSelection {
|
||||
attachClickEvent(this.selectionForwardBtn, () => {
|
||||
const obj: {[fromPeerId: PeerId]: number[]} = {};
|
||||
for(const [fromPeerId, mids] of this.selectedMids) {
|
||||
obj[fromPeerId] = Array.from(mids);
|
||||
obj[fromPeerId] = Array.from(mids).sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
new PopupForward(obj, () => {
|
||||
@ -897,7 +897,7 @@ export default class ChatSelection extends AppSelection {
|
||||
attachClickEvent(this.selectionForwardBtn, () => {
|
||||
const obj: {[fromPeerId: PeerId]: number[]} = {};
|
||||
for(const [fromPeerId, mids] of this.selectedMids) {
|
||||
obj[fromPeerId] = Array.from(mids);
|
||||
obj[fromPeerId] = Array.from(mids).sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
new PopupForward(obj, () => {
|
||||
|
@ -45,6 +45,7 @@ export default class CheckboxField {
|
||||
}
|
||||
|
||||
const input = this.input = document.createElement('input');
|
||||
input.classList.add('checkbox-field-input');
|
||||
input.type = 'checkbox';
|
||||
if(options.name) {
|
||||
input.id = 'input-' + options.name;
|
||||
|
@ -4,15 +4,15 @@
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
export default function RadioForm(radios: {container: HTMLElement, input: HTMLInputElement}[], onChange: (value: string) => void) {
|
||||
export default function RadioForm(radios: {container: HTMLElement, input: HTMLInputElement}[], onChange: (value: string, event: Event) => void) {
|
||||
const form = document.createElement('form');
|
||||
|
||||
radios.forEach(r => {
|
||||
const {container, input} = r;
|
||||
form.append(container);
|
||||
input.addEventListener('change', () => {
|
||||
input.addEventListener('change', (e) => {
|
||||
if(input.checked) {
|
||||
onChange(input.value);
|
||||
onChange(input.value, e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -19,7 +19,7 @@ const App = {
|
||||
version: process.env.VERSION,
|
||||
versionFull: process.env.VERSION_FULL,
|
||||
build: +process.env.BUILD,
|
||||
langPackVersion: '0.3.6',
|
||||
langPackVersion: '0.3.7',
|
||||
langPack: 'macos',
|
||||
langPackCode: 'en',
|
||||
domains: [MAIN_DOMAIN] as string[],
|
||||
|
27
src/lang.ts
27
src/lang.ts
@ -609,6 +609,33 @@ const lang = {
|
||||
"Contacts.PhoneNumber.NotRegistred": "The person with this phone number is not registered on Telegram yet.",
|
||||
"Channel.UsernameAboutChannel": "People can share this link with others and can find your channel using Telegram search.",
|
||||
"Channel.UsernameAboutGroup": "People can share this link with others and find your group using Telegram search.",
|
||||
"Chat.Accessory.Forward": {
|
||||
"one_value": "Forward Message",
|
||||
"other_value": "Forward %d Messages"
|
||||
},
|
||||
"Chat.Accessory.Forward.You": "You",
|
||||
"Chat.Accessory.Forward.From": "From",
|
||||
"Chat.Accessory.Hidden": {
|
||||
"one_value": "Forward Message (sender's name hidden)",
|
||||
"other_value": "Forward %d Messages (senders' names hidden)"
|
||||
},
|
||||
"Chat.Alert.Forward.Action.Another": "Forward to Another Chat",
|
||||
"Chat.Alert.Forward.Action.Hide1": {
|
||||
"one_value": "Hide Sender's Name",
|
||||
"other_value": "Hide Senders' Names"
|
||||
},
|
||||
"Chat.Alert.Forward.Action.Show1": {
|
||||
"one_value": "Show Sender's Name",
|
||||
"other_value": "Show Senders' Names"
|
||||
},
|
||||
"Chat.Alert.Forward.Action.ShowCaption": {
|
||||
"one_value": "Show Caption",
|
||||
"other_value": "Show Captions"
|
||||
},
|
||||
"Chat.Alert.Forward.Action.HideCaption": {
|
||||
"one_value": "Hide Caption",
|
||||
"other_value": "Hide Captions"
|
||||
},
|
||||
"Chat.CopySelectedText": "Copy Selected Text",
|
||||
"Chat.Confirm.Unpin": "Would you like to unpin this message?",
|
||||
"Chat.Date.ScheduledFor": "Scheduled for %@",
|
||||
|
@ -445,7 +445,7 @@ export class AppMessagesManager {
|
||||
scheduleDate: number,
|
||||
silent: true
|
||||
}> = {}) {
|
||||
if(typeof(text) !== 'string' || !text.length) {
|
||||
if(!text.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1538,7 +1538,7 @@ export class AppMessagesManager {
|
||||
}
|
||||
|
||||
private generateForwardHeader(peerId: PeerId, originalMessage: Message.message) {
|
||||
const myId = appUsersManager.getSelf().id;
|
||||
const myId = appUsersManager.getSelf().id.toPeerId();
|
||||
if(originalMessage.fromId === myId && originalMessage.peerId === myId && !originalMessage.fwd_from) {
|
||||
return;
|
||||
}
|
||||
@ -1891,24 +1891,44 @@ export class AppMessagesManager {
|
||||
public forwardMessages(peerId: PeerId, fromPeerId: PeerId, mids: number[], options: Partial<{
|
||||
withMyScore: true,
|
||||
silent: true,
|
||||
scheduleDate: number
|
||||
scheduleDate: number,
|
||||
dropAuthor: boolean,
|
||||
dropCaptions: boolean
|
||||
}> = {}) {
|
||||
peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;
|
||||
mids = mids.slice().sort((a, b) => a - b);
|
||||
|
||||
if(options.dropCaptions) {
|
||||
options.dropAuthor = true;
|
||||
}
|
||||
|
||||
const groups: {
|
||||
[groupId: string]: {
|
||||
tempId: string,
|
||||
messages: any[]
|
||||
messages: Message.message[]
|
||||
}
|
||||
} = {};
|
||||
|
||||
const newMessages = mids.map(mid => {
|
||||
const originalMessage: Message.message = this.getMessageByPeer(fromPeerId, mid);
|
||||
const message: Message.message = this.generateOutgoingMessage(peerId, options);
|
||||
message.fwd_from = this.generateForwardHeader(peerId, originalMessage);
|
||||
|
||||
(['entities', 'forwards', 'message', 'media', 'reply_markup', 'views'] as any as Array<keyof MyMessage>).forEach(key => {
|
||||
const keys: Array<keyof Message.message> = [
|
||||
'entities',
|
||||
'media',
|
||||
// 'reply_markup'
|
||||
];
|
||||
|
||||
if(!options.dropAuthor) {
|
||||
message.fwd_from = this.generateForwardHeader(peerId, originalMessage);
|
||||
keys.push('views', 'forwards');
|
||||
}
|
||||
|
||||
if(!options.dropCaptions) {
|
||||
keys.push('message');
|
||||
}
|
||||
|
||||
keys.forEach(key => {
|
||||
// @ts-ignore
|
||||
message[key] = originalMessage[key];
|
||||
});
|
||||
@ -1956,7 +1976,9 @@ export class AppMessagesManager {
|
||||
to_peer: appPeersManager.getInputPeerById(peerId),
|
||||
with_my_score: options.withMyScore,
|
||||
silent: options.silent,
|
||||
schedule_date: options.scheduleDate
|
||||
schedule_date: options.scheduleDate,
|
||||
drop_author: options.dropAuthor,
|
||||
drop_media_captions: options.dropCaptions
|
||||
}, sentRequestOptions).then((updates) => {
|
||||
this.log('forwardMessages updates:', updates);
|
||||
apiUpdatesManager.processUpdateMessage(updates);
|
||||
@ -2738,7 +2760,7 @@ export class AppMessagesManager {
|
||||
usingFullAlbum = false;
|
||||
}
|
||||
|
||||
if(!usingFullAlbum && !withoutMediaType) {
|
||||
if((!usingFullAlbum && !withoutMediaType) || !text) {
|
||||
const media = message.media;
|
||||
switch(media._) {
|
||||
case 'messageMediaPhoto':
|
||||
|
@ -553,7 +553,9 @@ export default class VideoPlayer extends EventListenerBase<{
|
||||
const buttons: Parameters<typeof ButtonMenu>[0] = [0.25, 0.5, 1, 1.25, 1.5, 2].map((rate) => {
|
||||
return {
|
||||
regularText: rate === 1 ? 'Normal' : '' + rate,
|
||||
onClick: () => this.video.playbackRate = rate
|
||||
onClick: () => {
|
||||
this.video.playbackRate = rate;
|
||||
}
|
||||
};
|
||||
});
|
||||
const btnMenu = ButtonMenu(buttons);
|
||||
|
@ -155,6 +155,10 @@
|
||||
transform-origin: bottom left;
|
||||
}
|
||||
|
||||
&.top-center {
|
||||
transform-origin: bottom center;
|
||||
}
|
||||
|
||||
&.center-left {
|
||||
transform-origin: center right;
|
||||
}
|
||||
@ -252,6 +256,11 @@
|
||||
margin-top: -.125rem;
|
||||
} */
|
||||
}
|
||||
|
||||
hr {
|
||||
padding: 0;
|
||||
margin: .5rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
|
@ -454,6 +454,8 @@ $chat-helper-size: 36px;
|
||||
|
||||
.reply-wrapper {
|
||||
height: 0 !important;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.btn-send {
|
||||
@ -988,12 +990,58 @@ $chat-helper-size: 36px;
|
||||
order: 0;
|
||||
pointer-events: none;
|
||||
|
||||
display: none;
|
||||
// display: none;
|
||||
}
|
||||
|
||||
&-cancel {
|
||||
// order: 2;
|
||||
order: 2;
|
||||
// order: 0;
|
||||
}
|
||||
|
||||
&-subtitle {
|
||||
color: var(--secondary-text-color) !important;
|
||||
}
|
||||
|
||||
.peer-title {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-menu {
|
||||
top: auto;
|
||||
bottom: calc(100% + 1.0625rem);
|
||||
left: 3.125rem;
|
||||
transform: scale(1) !important;
|
||||
|
||||
&-item {
|
||||
padding-right: 1.5rem;
|
||||
|
||||
&-text {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
&-field {
|
||||
--size: 1.5rem;
|
||||
order: 0;
|
||||
margin: 0 2rem 0 0;
|
||||
}
|
||||
|
||||
&-box {
|
||||
&-border,
|
||||
&-background {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-check use {
|
||||
stroke: var(--primary-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
left: calc(var(--padding-horizontal) * -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1620,6 +1620,7 @@ $bubble-beside-button-width: 38px;
|
||||
align-items: center;
|
||||
user-select: none;
|
||||
height: 1.125rem;
|
||||
line-height: 1;
|
||||
|
||||
&.can-autoplay:after {
|
||||
content: $tgico-nosound;
|
||||
|
@ -87,6 +87,7 @@
|
||||
stroke-dasharray: 24.19, 24.19;
|
||||
stroke-dashoffset: 0;
|
||||
transition: stroke-dasharray .1s .15s ease-in-out, visibility 0s .15s;
|
||||
visibility: visible; // fix blinking on parent's transform
|
||||
|
||||
@include animation-level(0) {
|
||||
transition: none !important;
|
||||
@ -262,7 +263,7 @@
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.checkbox-field [type="checkbox"] {
|
||||
.checkbox-field .checkbox-field-input {
|
||||
&:not(:checked) + .checkbox-box {
|
||||
.checkbox-box-check {
|
||||
use {
|
||||
|
@ -292,9 +292,12 @@ poll-element {
|
||||
font-size: 20px;
|
||||
line-height: 16px;
|
||||
animation: none;
|
||||
|
||||
@include animation-level(2) {
|
||||
transition: opacity .2s ease;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.animation-ring {
|
||||
display: block;
|
||||
|
Loading…
Reference in New Issue
Block a user