feat(client): methods for dialogs, also added support for drafts and clearing them
This commit is contained in:
parent
7a463f22a3
commit
e6dd822644
11 changed files with 493 additions and 11 deletions
|
@ -26,10 +26,12 @@ import { getChatMember } from './methods/chats/get-chat-member'
|
|||
import { getChatMembers } from './methods/chats/get-chat-members'
|
||||
import { getChatPreview } from './methods/chats/get-chat-preview'
|
||||
import { getChat } from './methods/chats/get-chat'
|
||||
import { getDialogs } from './methods/chats/get-dialogs'
|
||||
import { getFullChat } from './methods/chats/get-full-chat'
|
||||
import { iterChatMembers } from './methods/chats/iter-chat-members'
|
||||
import { joinChat } from './methods/chats/join-chat'
|
||||
import { leaveChat } from './methods/chats/leave-chat'
|
||||
import { saveDraft } from './methods/chats/save-draft'
|
||||
import { setChatDefaultPermissions } from './methods/chats/set-chat-default-permissions'
|
||||
import { setChatDescription } from './methods/chats/set-chat-description'
|
||||
import { setChatPhoto } from './methods/chats/set-chat-photo'
|
||||
|
@ -83,6 +85,7 @@ import {
|
|||
Chat,
|
||||
ChatMember,
|
||||
ChatPreview,
|
||||
Dialog,
|
||||
FileDownloadParameters,
|
||||
InputChatPermissions,
|
||||
InputFileLike,
|
||||
|
@ -560,6 +563,45 @@ export class TelegramClient extends BaseTelegramClient {
|
|||
getChat(chatId: InputPeerLike): Promise<Chat> {
|
||||
return getChat.apply(this, arguments)
|
||||
}
|
||||
/**
|
||||
* Get a chunk of dialogs
|
||||
*
|
||||
* You can get up to 100 dialogs at once
|
||||
*
|
||||
* @param params Fetch parameters
|
||||
*/
|
||||
getDialogs(params?: {
|
||||
/**
|
||||
* Offset date used as an anchor for pagination.
|
||||
*
|
||||
* Use {@link Dialog.date} for this value.
|
||||
*/
|
||||
offsetDate?: Date | number
|
||||
|
||||
/**
|
||||
* Limits the number of dialogs to be received.
|
||||
*
|
||||
* Defaults to 100.
|
||||
*/
|
||||
limit?: number
|
||||
|
||||
/**
|
||||
* How to handle pinned dialogs?
|
||||
* Whether to `include` them, `exclude`,
|
||||
* or `only` return pinned dialogs.
|
||||
*
|
||||
* Defaults to `include`
|
||||
*/
|
||||
pinned?: 'include' | 'exclude' | 'only'
|
||||
|
||||
/**
|
||||
* Whether to get dialogs from the
|
||||
* archived dialogs list.
|
||||
*/
|
||||
archived?: boolean
|
||||
}): Promise<Dialog[]> {
|
||||
return getDialogs.apply(this, arguments)
|
||||
}
|
||||
/**
|
||||
* Get full information about a chat.
|
||||
*
|
||||
|
@ -614,6 +656,18 @@ export class TelegramClient extends BaseTelegramClient {
|
|||
leaveChat(chatId: InputPeerLike, clear?: boolean): Promise<void> {
|
||||
return leaveChat.apply(this, arguments)
|
||||
}
|
||||
/**
|
||||
* Save or delete a draft message associated with some chat
|
||||
*
|
||||
* @param chatId ID of the chat, its username, phone or `"me"` or `"self"`
|
||||
* @param draft Draft message, or `null` to delete.
|
||||
*/
|
||||
saveDraft(
|
||||
chatId: InputPeerLike,
|
||||
draft: null | Omit<tl.RawDraftMessage, '_' | 'date'>
|
||||
): Promise<void> {
|
||||
return saveDraft.apply(this, arguments)
|
||||
}
|
||||
/**
|
||||
* Change default chat permissions for all members.
|
||||
*
|
||||
|
@ -1293,6 +1347,13 @@ export class TelegramClient extends BaseTelegramClient {
|
|||
* @param total Total file size
|
||||
*/
|
||||
progressCallback?: (uploaded: number, total: number) => void
|
||||
|
||||
/**
|
||||
* Whether to clear draft after sending this message.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
}
|
||||
): Promise<Message> {
|
||||
return sendMedia.apply(this, arguments)
|
||||
|
@ -1366,6 +1427,13 @@ export class TelegramClient extends BaseTelegramClient {
|
|||
* @param total Total file size
|
||||
*/
|
||||
progressCallback?: (uploaded: number, total: number) => void
|
||||
|
||||
/**
|
||||
* Whether to clear draft after sending this message.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
}
|
||||
): Promise<Message> {
|
||||
return sendPhoto.apply(this, arguments)
|
||||
|
@ -1423,6 +1491,13 @@ export class TelegramClient extends BaseTelegramClient {
|
|||
* to hide a reply keyboard or to force a reply.
|
||||
*/
|
||||
replyMarkup?: ReplyMarkup
|
||||
|
||||
/**
|
||||
* Whether to clear draft after sending this message.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
}
|
||||
): Promise<Message> {
|
||||
return sendText.apply(this, arguments)
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
Chat,
|
||||
ChatPreview,
|
||||
ChatMember,
|
||||
Dialog,
|
||||
InputChatPermissions,
|
||||
TermsOfService,
|
||||
SentCode,
|
||||
|
|
94
packages/client/src/methods/chats/get-dialogs.ts
Normal file
94
packages/client/src/methods/chats/get-dialogs.ts
Normal file
|
@ -0,0 +1,94 @@
|
|||
import { TelegramClient } from '../../client'
|
||||
import { Dialog } from '../../types'
|
||||
import { normalizeDate } from '../../utils/misc-utils'
|
||||
import { createUsersChatsIndex } from '../../utils/peer-utils'
|
||||
import { MtCuteTypeAssertionError } from '../../types'
|
||||
import { tl } from '@mtcute/tl'
|
||||
import { getMarkedPeerId } from '@mtcute/core'
|
||||
|
||||
/**
|
||||
* Get a chunk of dialogs
|
||||
*
|
||||
* You can get up to 100 dialogs at once
|
||||
*
|
||||
* @param params Fetch parameters
|
||||
* @internal
|
||||
*/
|
||||
export async function getDialogs(
|
||||
this: TelegramClient,
|
||||
params?: {
|
||||
/**
|
||||
* Offset date used as an anchor for pagination.
|
||||
*
|
||||
* Use {@link Dialog.date} for this value.
|
||||
*/
|
||||
offsetDate?: Date | number
|
||||
|
||||
/**
|
||||
* Limits the number of dialogs to be received.
|
||||
*
|
||||
* Defaults to 100.
|
||||
*/
|
||||
limit?: number
|
||||
|
||||
/**
|
||||
* How to handle pinned dialogs?
|
||||
* Whether to `include` them, `exclude`,
|
||||
* or `only` return pinned dialogs.
|
||||
*
|
||||
* Defaults to `include`
|
||||
*/
|
||||
pinned?: 'include' | 'exclude' | 'only'
|
||||
|
||||
/**
|
||||
* Whether to get dialogs from the
|
||||
* archived dialogs list.
|
||||
*/
|
||||
archived?: boolean
|
||||
}
|
||||
): Promise<Dialog[]> {
|
||||
if (!params) params = {}
|
||||
|
||||
let res
|
||||
if (params.pinned === 'only') {
|
||||
res = await this.call({
|
||||
_: 'messages.getPinnedDialogs',
|
||||
folderId: params.archived ? 1 : 0,
|
||||
})
|
||||
} else {
|
||||
res = await this.call({
|
||||
_: 'messages.getDialogs',
|
||||
excludePinned: params.pinned === 'exclude',
|
||||
folderId: params.archived ? 1 : 0,
|
||||
offsetDate: normalizeDate(params.offsetDate) ?? 0,
|
||||
|
||||
// offseting by id and peer is useless because when some peer sends
|
||||
// a message, their dialog goes to the top and we get a cycle
|
||||
offsetId: 0,
|
||||
offsetPeer: { _: 'inputPeerEmpty' },
|
||||
|
||||
limit: params.limit ?? 100,
|
||||
hash: 0,
|
||||
})
|
||||
}
|
||||
|
||||
if (res._ === 'messages.dialogsNotModified')
|
||||
throw new MtCuteTypeAssertionError(
|
||||
'getDialogs',
|
||||
'!messages.dialogsNotModified',
|
||||
'messages.dialogsNotModified'
|
||||
)
|
||||
|
||||
const { users, chats } = createUsersChatsIndex(res)
|
||||
|
||||
const messages: Record<number, tl.TypeMessage> = {}
|
||||
res.messages.forEach((msg) => {
|
||||
if (!msg.peerId) return
|
||||
|
||||
messages[getMarkedPeerId(msg.peerId)] = msg
|
||||
})
|
||||
|
||||
return res.dialogs
|
||||
.filter(it => it._ === 'dialog')
|
||||
.map(it => new Dialog(this, it as tl.RawDialog, users, chats, messages))
|
||||
}
|
33
packages/client/src/methods/chats/save-draft.ts
Normal file
33
packages/client/src/methods/chats/save-draft.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { TelegramClient } from '../../client'
|
||||
import { InputPeerLike } from '../../types'
|
||||
import { tl } from '@mtcute/tl'
|
||||
import { normalizeToInputPeer } from '../../utils/peer-utils'
|
||||
|
||||
/**
|
||||
* Save or delete a draft message associated with some chat
|
||||
*
|
||||
* @param chatId ID of the chat, its username, phone or `"me"` or `"self"`
|
||||
* @param draft Draft message, or `null` to delete.
|
||||
* @internal
|
||||
*/
|
||||
export async function saveDraft(
|
||||
this: TelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
draft: null | Omit<tl.RawDraftMessage, '_' | 'date'>
|
||||
): Promise<void> {
|
||||
const peer = normalizeToInputPeer(await this.resolvePeer(chatId))
|
||||
|
||||
if (draft) {
|
||||
await this.call({
|
||||
_: 'messages.saveDraft',
|
||||
peer,
|
||||
...draft
|
||||
})
|
||||
} else {
|
||||
await this.call({
|
||||
_: 'messages.saveDraft',
|
||||
peer,
|
||||
message: ''
|
||||
})
|
||||
}
|
||||
}
|
|
@ -65,6 +65,13 @@ export async function sendMedia(
|
|||
* @param total Total file size
|
||||
*/
|
||||
progressCallback?: (uploaded: number, total: number) => void
|
||||
|
||||
/**
|
||||
* Whether to clear draft after sending this message.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
}
|
||||
): Promise<Message> {
|
||||
if (!params) params = {}
|
||||
|
@ -143,9 +150,10 @@ export async function sendMedia(
|
|||
w: media.width || 0,
|
||||
h: media.height || 0,
|
||||
supportsStreaming: media.supportsStreaming,
|
||||
roundMessage: media.isRound
|
||||
roundMessage: media.isRound,
|
||||
})
|
||||
if (media.isAnimated) attributes.push({ _: 'documentAttributeAnimated' })
|
||||
if (media.isAnimated)
|
||||
attributes.push({ _: 'documentAttributeAnimated' })
|
||||
}
|
||||
|
||||
if (media.type === 'audio' || media.type === 'voice') {
|
||||
|
@ -155,7 +163,7 @@ export async function sendMedia(
|
|||
duration: media.duration || 0,
|
||||
title: media.type === 'audio' ? media.title : undefined,
|
||||
performer: media.type === 'audio' ? media.performer : undefined,
|
||||
waveform: media.type === 'voice' ? media.waveform : undefined
|
||||
waveform: media.type === 'voice' ? media.waveform : undefined,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -166,7 +174,7 @@ export async function sendMedia(
|
|||
file: inputFile,
|
||||
thumb,
|
||||
mimeType: mime,
|
||||
attributes
|
||||
attributes,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,7 +187,6 @@ export async function sendMedia(
|
|||
const peer = normalizeToInputPeer(await this.resolvePeer(chatId))
|
||||
const replyMarkup = BotKeyboard._convertToTl(params.replyMarkup)
|
||||
|
||||
|
||||
const res = await this.call({
|
||||
_: 'messages.sendMedia',
|
||||
peer,
|
||||
|
@ -195,6 +202,7 @@ export async function sendMedia(
|
|||
replyMarkup,
|
||||
message,
|
||||
entities,
|
||||
clearDraft: params.clearDraft,
|
||||
})
|
||||
|
||||
return this._findMessageInUpdate(res)
|
||||
|
|
|
@ -82,6 +82,13 @@ export async function sendPhoto(
|
|||
* @param total Total file size
|
||||
*/
|
||||
progressCallback?: (uploaded: number, total: number) => void
|
||||
|
||||
/**
|
||||
* Whether to clear draft after sending this message.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
}
|
||||
): Promise<Message> {
|
||||
if (!params) params = {}
|
||||
|
@ -141,6 +148,7 @@ export async function sendPhoto(
|
|||
replyMarkup,
|
||||
message,
|
||||
entities,
|
||||
clearDraft: params.clearDraft,
|
||||
})
|
||||
|
||||
return this._findMessageInUpdate(res)
|
||||
|
|
|
@ -2,12 +2,7 @@ import { TelegramClient } from '../../client'
|
|||
import { tl } from '@mtcute/tl'
|
||||
import { inputPeerToPeer, normalizeToInputPeer } from '../../utils/peer-utils'
|
||||
import { normalizeDate, randomUlong } from '../../utils/misc-utils'
|
||||
import {
|
||||
InputPeerLike,
|
||||
Message,
|
||||
BotKeyboard,
|
||||
ReplyMarkup,
|
||||
} from '../../types'
|
||||
import { InputPeerLike, Message, BotKeyboard, ReplyMarkup } from '../../types'
|
||||
|
||||
/**
|
||||
* Send a text message
|
||||
|
@ -64,6 +59,13 @@ export async function sendText(
|
|||
* to hide a reply keyboard or to force a reply.
|
||||
*/
|
||||
replyMarkup?: ReplyMarkup
|
||||
|
||||
/**
|
||||
* Whether to clear draft after sending this message.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
clearDraft?: boolean
|
||||
}
|
||||
): Promise<Message> {
|
||||
if (!params) params = {}
|
||||
|
@ -92,6 +94,7 @@ export async function sendText(
|
|||
replyMarkup,
|
||||
message,
|
||||
entities,
|
||||
clearDraft: params.clearDraft,
|
||||
})
|
||||
|
||||
if (res._ === 'updateShortSentMessage') {
|
||||
|
|
133
packages/client/src/types/messages/dialog.ts
Normal file
133
packages/client/src/types/messages/dialog.ts
Normal file
|
@ -0,0 +1,133 @@
|
|||
import { TelegramClient } from '../../client'
|
||||
import { tl } from '@mtcute/tl'
|
||||
import { Chat } from '../peers'
|
||||
import { Message } from './message'
|
||||
import { DraftMessage } from './draft-message'
|
||||
import { makeInspectable } from '../utils'
|
||||
|
||||
/**
|
||||
* A dialog.
|
||||
*
|
||||
* Think of it as something that is listed
|
||||
* in Telegram's main window.
|
||||
*/
|
||||
export class Dialog {
|
||||
readonly client: TelegramClient
|
||||
readonly raw: tl.RawDialog
|
||||
|
||||
/** Map of users in this object. Mainly for internal use */
|
||||
readonly _users: Record<number, tl.TypeUser>
|
||||
|
||||
/** Map of chats in this object. Mainly for internal use */
|
||||
readonly _chats: Record<number, tl.TypeChat>
|
||||
|
||||
/** Map of messages in this object. Mainly for internal use */
|
||||
readonly _messages: Record<number, tl.TypeMessage>
|
||||
|
||||
constructor(
|
||||
client: TelegramClient,
|
||||
raw: tl.RawDialog,
|
||||
users: Record<number, tl.TypeUser>,
|
||||
chats: Record<number, tl.TypeChat>,
|
||||
messages: Record<number, tl.TypeMessage>
|
||||
) {
|
||||
this.client = client
|
||||
this.raw = raw
|
||||
this._users = users
|
||||
this._chats = chats
|
||||
this._messages = messages
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this dialog is pinned
|
||||
*/
|
||||
get isPinned(): boolean {
|
||||
return !!this.raw.pinned
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this chat was manually marked as unread
|
||||
*/
|
||||
get isManuallyUnread(): boolean {
|
||||
return !!this.raw.unreadMark
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this chat should be considered unread
|
||||
* (i.e. has more than 1 unread message, or has
|
||||
* a "manually unread" mark)
|
||||
*/
|
||||
get isUnread(): boolean {
|
||||
return this.raw.unreadMark || this.raw.unreadCount > 1
|
||||
}
|
||||
|
||||
private _chat?: Chat
|
||||
/**
|
||||
* Chat that this dialog represents
|
||||
*/
|
||||
get chat(): Chat {
|
||||
if (!this._chat) {
|
||||
const peer = this.raw.peer
|
||||
|
||||
let chat
|
||||
if (peer._ === 'peerChannel' || peer._ === 'peerChat') {
|
||||
chat = this._chats[peer._ === 'peerChannel' ? peer.channelId : peer.chatId]
|
||||
} else {
|
||||
chat = this._users[peer.userId]
|
||||
}
|
||||
|
||||
this._chat = new Chat(this.client, chat)
|
||||
}
|
||||
|
||||
return this._chat
|
||||
}
|
||||
|
||||
private _lastMessage?: Message | null
|
||||
/**
|
||||
* The latest message sent in this chat
|
||||
*/
|
||||
get lastMessage(): Message | null {
|
||||
if (this._lastMessage === undefined) {
|
||||
const cid = this.chat.id
|
||||
if (cid in this._messages) {
|
||||
this._lastMessage = new Message(this.client, this._messages[cid], this._users, this._chats)
|
||||
} else {
|
||||
this._lastMessage = null
|
||||
}
|
||||
}
|
||||
|
||||
return this._lastMessage
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of unread messages
|
||||
*/
|
||||
get unreadCount(): number {
|
||||
return this.raw.unreadCount
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of unread messages
|
||||
*/
|
||||
get unreadMentionsCount(): number {
|
||||
return this.raw.unreadMentionsCount
|
||||
}
|
||||
|
||||
private _draftMessage?: DraftMessage | null
|
||||
/**
|
||||
* Draft message in this dialog
|
||||
*/
|
||||
get draftMessage(): DraftMessage | null {
|
||||
if (this._draftMessage === undefined) {
|
||||
if (this.raw.draft?._ === 'draftMessage') {
|
||||
this._draftMessage = new DraftMessage(this.client, this.raw.draft, this.chat.inputPeer)
|
||||
} else {
|
||||
this._draftMessage = null
|
||||
}
|
||||
}
|
||||
|
||||
return this._draftMessage
|
||||
}
|
||||
}
|
||||
|
||||
makeInspectable(Dialog)
|
120
packages/client/src/types/messages/draft-message.ts
Normal file
120
packages/client/src/types/messages/draft-message.ts
Normal file
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* A draft message
|
||||
*/
|
||||
import { tl } from '@mtcute/tl'
|
||||
import { TelegramClient } from '../../client'
|
||||
import { MessageEntity } from './message-entity'
|
||||
import { Message } from './message'
|
||||
import { InputPeerLike } from '../peers'
|
||||
import { makeInspectable } from '../utils'
|
||||
import { InputMediaLike } from '../media'
|
||||
|
||||
export class DraftMessage {
|
||||
readonly client: TelegramClient
|
||||
readonly raw: tl.RawDraftMessage
|
||||
|
||||
private _chatId: InputPeerLike
|
||||
|
||||
constructor(
|
||||
client: TelegramClient,
|
||||
raw: tl.RawDraftMessage,
|
||||
chatId: InputPeerLike
|
||||
) {
|
||||
this.client = client
|
||||
this.raw = raw
|
||||
this._chatId = chatId
|
||||
}
|
||||
|
||||
/**
|
||||
* Text of the draft message
|
||||
*/
|
||||
get text(): string {
|
||||
return this.raw.message
|
||||
}
|
||||
|
||||
/**
|
||||
* The message this message will reply to
|
||||
*/
|
||||
get replyToMessageId(): number | null {
|
||||
return this.raw.replyToMsgId ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
* Date of the last time this draft was updated
|
||||
*/
|
||||
get date(): Date {
|
||||
return new Date(this.raw.date * 1000)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether no webpage preview will be generated
|
||||
*/
|
||||
get disableWebPreview(): boolean {
|
||||
return !!this.raw.noWebpage
|
||||
}
|
||||
|
||||
private _entities?: MessageEntity[]
|
||||
/**
|
||||
* Message text entities (may be empty)
|
||||
*/
|
||||
get entities(): MessageEntity[] {
|
||||
if (!this._entities) {
|
||||
this._entities = []
|
||||
if (this.raw.entities?.length) {
|
||||
for (const ent of this.raw.entities) {
|
||||
const parsed = MessageEntity._parse(ent)
|
||||
if (parsed) this._entities.push(parsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this._entities
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this draft as a message.
|
||||
* Calling this method will clear current draft.
|
||||
*
|
||||
* @param params Additional sending parameters
|
||||
* @link TelegramClient.sendText
|
||||
*/
|
||||
send(params?: Parameters<TelegramClient['sendText']>[2]): Promise<Message> {
|
||||
return this.client.sendText(this._chatId, this.raw.message, {
|
||||
clearDraft: true,
|
||||
disableWebPreview: this.raw.noWebpage,
|
||||
entities: this.raw.entities,
|
||||
replyTo: this.raw.replyToMsgId,
|
||||
...(params || {}),
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this draft as a message with media.
|
||||
* Calling this method will clear current draft.
|
||||
*
|
||||
* If passed media does not have an
|
||||
* explicit caption, it will be set to {@link text},
|
||||
* and its entities to {@link entities}
|
||||
*
|
||||
* @param media Media to be sent
|
||||
* @param params Additional sending parameters
|
||||
* @link TelegramClient.sendMedia
|
||||
*/
|
||||
sendWithMedia(
|
||||
media: InputMediaLike,
|
||||
params?: Parameters<TelegramClient['sendMedia']>[2]
|
||||
): Promise<Message> {
|
||||
if (!media.caption) {
|
||||
media.caption = this.raw.message
|
||||
media.entities = this.raw.entities
|
||||
}
|
||||
|
||||
return this.client.sendMedia(this._chatId, media, {
|
||||
clearDraft: true,
|
||||
replyTo: this.raw.replyToMsgId,
|
||||
...(params || {}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
makeInspectable(DraftMessage)
|
|
@ -1,3 +1,5 @@
|
|||
export * from './message-entity'
|
||||
export * from './message'
|
||||
export * from './search-filters'
|
||||
export * from './draft-message'
|
||||
export * from './dialog'
|
||||
|
|
|
@ -163,6 +163,11 @@ export class Chat {
|
|||
return this.peer._ === 'user' && this.peer.support!
|
||||
}
|
||||
|
||||
/** Whether this chat is chat with yourself (i.e. Saved Messages) */
|
||||
get isSelf(): boolean {
|
||||
return this.peer._ === 'user' && this.peer.self!
|
||||
}
|
||||
|
||||
/**
|
||||
* Title, for supergroups, channels and groups
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue