Avatar context menu
This commit is contained in:
parent
5af49d55f1
commit
f14a235b81
|
@ -49,6 +49,7 @@ import getMediaFromMessage from '../../lib/appManagers/utils/messages/getMediaFr
|
|||
import canSaveMessageMedia from '../../lib/appManagers/utils/messages/canSaveMessageMedia';
|
||||
import getAlbumText from '../../lib/appManagers/utils/messages/getAlbumText';
|
||||
import PopupElement from '../popups';
|
||||
import AvatarElement from '../avatar';
|
||||
|
||||
type ChatContextMenuButton = ButtonMenuItemOptions & {
|
||||
verify: () => boolean | Promise<boolean>,
|
||||
|
@ -90,6 +91,7 @@ export default class ChatContextMenu {
|
|||
private linkToMessage: Awaited<ReturnType<ChatContextMenu['getUrlToMessage']>>;
|
||||
private selectedMessagesText: string;
|
||||
private selectedMessages: MyMessage[];
|
||||
private avatarPeerId: number;
|
||||
|
||||
constructor(
|
||||
private chat: Chat,
|
||||
|
@ -117,7 +119,7 @@ export default class ChatContextMenu {
|
|||
'.reply',
|
||||
'.document',
|
||||
'audio-element',
|
||||
'avatar-element',
|
||||
// 'avatar-element',
|
||||
'a',
|
||||
'.bubble-beside-button',
|
||||
'replies-element',
|
||||
|
@ -142,15 +144,16 @@ export default class ChatContextMenu {
|
|||
}
|
||||
|
||||
private onContextMenu = (e: MouseEvent | Touch | TouchEvent) => {
|
||||
let bubble: HTMLElement, contentWrapper: HTMLElement;
|
||||
let bubble: HTMLElement, contentWrapper: HTMLElement, avatar: AvatarElement;
|
||||
|
||||
try {
|
||||
contentWrapper = findUpClassName(e.target, 'bubble-content-wrapper');
|
||||
bubble = contentWrapper ? contentWrapper.parentElement : findUpClassName(e.target, 'bubble');
|
||||
avatar = findUpClassName(e.target, 'bubbles-group-avatar') as AvatarElement;
|
||||
} catch(e) {}
|
||||
|
||||
// ! context menu click by date bubble (there is no pointer-events)
|
||||
if(!bubble || bubble.classList.contains('bubble-first')) return;
|
||||
if((!bubble || bubble.classList.contains('bubble-first')) && !avatar) return;
|
||||
|
||||
let element = this.element;
|
||||
if(e instanceof MouseEvent || e.hasOwnProperty('preventDefault')) (e as any).preventDefault();
|
||||
|
@ -159,8 +162,10 @@ export default class ChatContextMenu {
|
|||
}
|
||||
if(e instanceof MouseEvent || e.hasOwnProperty('cancelBubble')) (e as any).cancelBubble = true;
|
||||
|
||||
let mid = +bubble.dataset.mid;
|
||||
if(!mid) return;
|
||||
let mid = avatar ? 0 : +bubble.dataset.mid;
|
||||
if(!mid && mid !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const r = async() => {
|
||||
const isSponsored = this.isSponsored = mid < 0;
|
||||
|
@ -177,9 +182,9 @@ export default class ChatContextMenu {
|
|||
|
||||
this.sponsoredMessage = isSponsored ? (bubble as any).message.sponsoredMessage : undefined;
|
||||
|
||||
const mids = await this.chat.getMidsByMid(mid);
|
||||
const mids = avatar ? [] : await this.chat.getMidsByMid(mid);
|
||||
// * если открыть контекстное меню для альбома не по бабблу, и последний элемент не выбран, чтобы показать остальные пункты
|
||||
if(this.chat.selection.isSelecting && !contentWrapper) {
|
||||
if(this.chat.selection.isSelecting && !contentWrapper && mid) {
|
||||
if(isSponsored) {
|
||||
return;
|
||||
}
|
||||
|
@ -196,6 +201,8 @@ export default class ChatContextMenu {
|
|||
|
||||
this.isOverBubble = !!contentWrapper;
|
||||
|
||||
this.avatarPeerId = (avatar as AvatarElement)?.peerId;
|
||||
|
||||
const groupedItem = findUpClassName(this.target, 'grouped-item');
|
||||
this.isTargetAGroupedItem = !!groupedItem;
|
||||
if(groupedItem) {
|
||||
|
@ -205,14 +212,14 @@ export default class ChatContextMenu {
|
|||
}
|
||||
|
||||
this.isSelected = this.chat.selection.isMidSelected(this.peerId, this.mid);
|
||||
this.message = (bubble as any).message || await this.chat.getMessage(this.mid);
|
||||
this.albumMessages = (this.message as Message.message).grouped_id ? await this.managers.appMessagesManager.getMessagesByAlbum((this.message as Message.message).grouped_id) : undefined;
|
||||
this.noForwards = !isSponsored && !(await this.managers.appMessagesManager.canForward(this.message));
|
||||
this.message = avatar ? undefined : (bubble as any).message || await this.chat.getMessage(this.mid);
|
||||
this.albumMessages = (this.message as Message.message)?.grouped_id ? await this.managers.appMessagesManager.getMessagesByAlbum((this.message as Message.message).grouped_id) : undefined;
|
||||
this.noForwards = this.message && !isSponsored && !(await this.managers.appMessagesManager.canForward(this.message));
|
||||
this.viewerPeerId = undefined;
|
||||
this.canOpenReactedList = undefined;
|
||||
this.linkToMessage = await this.getUrlToMessage();
|
||||
this.selectedMessagesText = await this.getSelectedMessagesText();
|
||||
this.selectedMessages = this.chat.selection.isSelecting ? await this.chat.selection.getSelectedMessages() : undefined;
|
||||
this.selectedMessages = this.chat.selection.isSelecting && !avatar ? await this.chat.selection.getSelectedMessages() : undefined;
|
||||
|
||||
const initResult = await this.init();
|
||||
if(!initResult) {
|
||||
|
@ -242,7 +249,7 @@ export default class ChatContextMenu {
|
|||
}
|
||||
}
|
||||
|
||||
const side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right';
|
||||
const side: 'left' | 'right' = !bubble || bubble.classList.contains('is-in') ? 'left' : 'right';
|
||||
// bubble.parentElement.append(element);
|
||||
// appImManager.log('contextmenu', e, bubble, side);
|
||||
positionMenu((e as TouchEvent).touches ? (e as TouchEvent).touches[0] : e as MouseEvent, element, side, menuPadding);
|
||||
|
@ -313,6 +320,36 @@ export default class ChatContextMenu {
|
|||
}
|
||||
|
||||
private setButtons() {
|
||||
if(this.avatarPeerId !== undefined) {
|
||||
const openPeer = () => {
|
||||
this.chat.appImManager.setInnerPeer({peerId: this.avatarPeerId});
|
||||
};
|
||||
this.buttons = [{
|
||||
icon: 'message',
|
||||
text: 'SendMessage',
|
||||
onClick: openPeer,
|
||||
verify: () => this.chat.peerId !== this.avatarPeerId && this.avatarPeerId.isUser()
|
||||
}, {
|
||||
icon: 'newgroup',
|
||||
text: 'OpenGroup2',
|
||||
onClick: openPeer,
|
||||
verify: () => this.chat.peerId !== this.avatarPeerId && this.managers.appPeersManager.isAnyGroup(this.avatarPeerId)
|
||||
}, {
|
||||
icon: 'newchannel',
|
||||
text: 'OpenChannel2',
|
||||
onClick: openPeer,
|
||||
verify: () => this.chat.peerId !== this.avatarPeerId && this.managers.appPeersManager.isBroadcast(this.avatarPeerId)
|
||||
}, {
|
||||
icon: 'mention',
|
||||
text: 'Mention',
|
||||
onClick: () => {
|
||||
this.chat.input.mentionUser(this.avatarPeerId.toUserId(), false);
|
||||
},
|
||||
verify: () => /* this.avatarPeerId.isUser() && */this.chat.canSend('send_plain')
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
const verifyFavoriteSticker = async(toAdd: boolean) => {
|
||||
const doc = ((this.message as Message.message).media as MessageMedia.messageMediaDocument)?.document;
|
||||
if(!(doc as MyDocument)?.sticker) {
|
||||
|
@ -770,7 +807,7 @@ export default class ChatContextMenu {
|
|||
let reactionsMenu: ChatReactionsMenu;
|
||||
let reactionsMenuPosition: 'horizontal' | 'vertical';
|
||||
if(
|
||||
this.message._ === 'message' &&
|
||||
this.message?._ === 'message' &&
|
||||
!this.chat.selection.isSelecting &&
|
||||
!this.message.pFlags.is_outgoing &&
|
||||
!this.message.pFlags.is_scheduled &&
|
||||
|
@ -868,7 +905,7 @@ export default class ChatContextMenu {
|
|||
}
|
||||
|
||||
private async getUrlToMessage() {
|
||||
if(this.peerId.isUser()) {
|
||||
if(!this.message || this.peerId.isUser()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -898,7 +935,7 @@ export default class ChatContextMenu {
|
|||
}
|
||||
|
||||
private async getSelectedMessagesText() {
|
||||
if(!isSelectionEmpty()) {
|
||||
if(this.avatarPeerId || !isSelectionEmpty()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ import {MARKDOWN_ENTITIES} from '../../lib/richTextProcessor';
|
|||
import IMAGE_MIME_TYPES_SUPPORTED from '../../environment/imageMimeTypesSupport';
|
||||
import VIDEO_MIME_TYPES_SUPPORTED from '../../environment/videoMimeTypesSupport';
|
||||
import {ChatRights} from '../../lib/appManagers/appChatsManager';
|
||||
import getPeerActiveUsernames from '../../lib/appManagers/utils/peers/getPeerActiveUsernames';
|
||||
|
||||
const RECORD_MIN_TIME = 500;
|
||||
|
||||
|
@ -1296,6 +1297,27 @@ export default class ChatInput {
|
|||
this.managers.appDraftsManager.syncDraft(this.chat.peerId, this.chat.threadId, draft);
|
||||
}
|
||||
|
||||
public mentionUser(userId: UserId, isHelper?: boolean) {
|
||||
Promise.resolve(this.managers.appUsersManager.getUser(userId)).then((user) => {
|
||||
let str = '', entity: MessageEntity;
|
||||
const usernames = getPeerActiveUsernames(user);
|
||||
if(usernames[0]) {
|
||||
str = '@' + usernames[0];
|
||||
} else {
|
||||
str = user.first_name || user.last_name;
|
||||
entity = {
|
||||
_: 'messageEntityMentionName',
|
||||
length: str.length,
|
||||
offset: 0,
|
||||
user_id: user.id
|
||||
};
|
||||
}
|
||||
|
||||
str += ' ';
|
||||
this.insertAtCaret(str, entity, isHelper);
|
||||
});
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
// this.chat.log.error('Input destroying');
|
||||
|
||||
|
@ -2185,7 +2207,7 @@ export default class ChatInput {
|
|||
const newValue = newPrefix + insertText + suffix;
|
||||
|
||||
if(isHelper && caretPos !== -1) {
|
||||
const match = matches[2];
|
||||
const match = matches ? matches[2] : fullValue;
|
||||
// const {node, selection} = getCaretPosNew(this.messageInput);
|
||||
|
||||
const selection = document.getSelection();
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
import type ChatInput from './input';
|
||||
import type {MessageEntity} from '../../layer';
|
||||
import AutocompleteHelperController from './autocompleteHelperController';
|
||||
import AutocompletePeerHelper from './autocompletePeerHelper';
|
||||
import {AppManagers} from '../../lib/appManagers/managers';
|
||||
|
@ -25,24 +24,7 @@ export default class MentionsHelper extends AutocompletePeerHelper {
|
|||
'mentions-helper',
|
||||
(target) => {
|
||||
const userId = (target as HTMLElement).dataset.peerId.toUserId();
|
||||
const user = Promise.resolve(managers.appUsersManager.getUser(userId)).then((user) => {
|
||||
let str = '', entity: MessageEntity;
|
||||
const usernames = getPeerActiveUsernames(user);
|
||||
if(usernames[0]) {
|
||||
str = '@' + usernames[0];
|
||||
} else {
|
||||
str = user.first_name || user.last_name;
|
||||
entity = {
|
||||
_: 'messageEntityMentionName',
|
||||
length: str.length,
|
||||
offset: 0,
|
||||
user_id: user.id
|
||||
};
|
||||
}
|
||||
|
||||
str += ' ';
|
||||
chatInput.insertAtCaret(str, entity);
|
||||
});
|
||||
chatInput.mentionUser(userId, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -890,7 +890,8 @@ export default class ChatSelection extends AppSelection {
|
|||
}
|
||||
|
||||
public canSelectBubble(bubble: HTMLElement) {
|
||||
return !bubble.classList.contains('service') &&
|
||||
return bubble &&
|
||||
!bubble.classList.contains('service') &&
|
||||
!bubble.classList.contains('is-outgoing') &&
|
||||
!bubble.classList.contains('is-error') &&
|
||||
!bubble.classList.contains('bubble-first') &&
|
||||
|
|
|
@ -21,7 +21,7 @@ const App = {
|
|||
version: process.env.VERSION,
|
||||
versionFull: process.env.VERSION_FULL,
|
||||
build: +process.env.BUILD,
|
||||
langPackVersion: '1.0.7',
|
||||
langPackVersion: '1.0.8',
|
||||
langPack: 'webk',
|
||||
langPackCode: 'en',
|
||||
domains: MAIN_DOMAINS,
|
||||
|
|
|
@ -955,6 +955,10 @@ const lang = {
|
|||
'BotAlreadyAddedToAttachMenu': 'This bot is already added to your attachment menu.',
|
||||
'AddBot': 'Add Bot',
|
||||
'ActionAttachMenuBotAllowed': 'You allowed this bot to message you when you added it to your attachment menu.',
|
||||
'SendMessage': 'Send Message',
|
||||
'Mention': 'Mention',
|
||||
'OpenChannel2': 'Open Channel',
|
||||
'OpenGroup2': 'Open Group',
|
||||
|
||||
// * macos
|
||||
'AccountSettings.Filters': 'Chat Folders',
|
||||
|
|
Loading…
Reference in New Issue