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 { getChatMembers } from './methods/chats/get-chat-members'
|
||||||
import { getChatPreview } from './methods/chats/get-chat-preview'
|
import { getChatPreview } from './methods/chats/get-chat-preview'
|
||||||
import { getChat } from './methods/chats/get-chat'
|
import { getChat } from './methods/chats/get-chat'
|
||||||
|
import { getDialogs } from './methods/chats/get-dialogs'
|
||||||
import { getFullChat } from './methods/chats/get-full-chat'
|
import { getFullChat } from './methods/chats/get-full-chat'
|
||||||
import { iterChatMembers } from './methods/chats/iter-chat-members'
|
import { iterChatMembers } from './methods/chats/iter-chat-members'
|
||||||
import { joinChat } from './methods/chats/join-chat'
|
import { joinChat } from './methods/chats/join-chat'
|
||||||
import { leaveChat } from './methods/chats/leave-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 { setChatDefaultPermissions } from './methods/chats/set-chat-default-permissions'
|
||||||
import { setChatDescription } from './methods/chats/set-chat-description'
|
import { setChatDescription } from './methods/chats/set-chat-description'
|
||||||
import { setChatPhoto } from './methods/chats/set-chat-photo'
|
import { setChatPhoto } from './methods/chats/set-chat-photo'
|
||||||
|
@ -83,6 +85,7 @@ import {
|
||||||
Chat,
|
Chat,
|
||||||
ChatMember,
|
ChatMember,
|
||||||
ChatPreview,
|
ChatPreview,
|
||||||
|
Dialog,
|
||||||
FileDownloadParameters,
|
FileDownloadParameters,
|
||||||
InputChatPermissions,
|
InputChatPermissions,
|
||||||
InputFileLike,
|
InputFileLike,
|
||||||
|
@ -560,6 +563,45 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
getChat(chatId: InputPeerLike): Promise<Chat> {
|
getChat(chatId: InputPeerLike): Promise<Chat> {
|
||||||
return getChat.apply(this, arguments)
|
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.
|
* Get full information about a chat.
|
||||||
*
|
*
|
||||||
|
@ -614,6 +656,18 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
leaveChat(chatId: InputPeerLike, clear?: boolean): Promise<void> {
|
leaveChat(chatId: InputPeerLike, clear?: boolean): Promise<void> {
|
||||||
return leaveChat.apply(this, arguments)
|
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.
|
* Change default chat permissions for all members.
|
||||||
*
|
*
|
||||||
|
@ -1293,6 +1347,13 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
* @param total Total file size
|
* @param total Total file size
|
||||||
*/
|
*/
|
||||||
progressCallback?: (uploaded: number, total: number) => void
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to clear draft after sending this message.
|
||||||
|
*
|
||||||
|
* Defaults to `false`
|
||||||
|
*/
|
||||||
|
clearDraft?: boolean
|
||||||
}
|
}
|
||||||
): Promise<Message> {
|
): Promise<Message> {
|
||||||
return sendMedia.apply(this, arguments)
|
return sendMedia.apply(this, arguments)
|
||||||
|
@ -1366,6 +1427,13 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
* @param total Total file size
|
* @param total Total file size
|
||||||
*/
|
*/
|
||||||
progressCallback?: (uploaded: number, total: number) => void
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to clear draft after sending this message.
|
||||||
|
*
|
||||||
|
* Defaults to `false`
|
||||||
|
*/
|
||||||
|
clearDraft?: boolean
|
||||||
}
|
}
|
||||||
): Promise<Message> {
|
): Promise<Message> {
|
||||||
return sendPhoto.apply(this, arguments)
|
return sendPhoto.apply(this, arguments)
|
||||||
|
@ -1423,6 +1491,13 @@ export class TelegramClient extends BaseTelegramClient {
|
||||||
* to hide a reply keyboard or to force a reply.
|
* to hide a reply keyboard or to force a reply.
|
||||||
*/
|
*/
|
||||||
replyMarkup?: ReplyMarkup
|
replyMarkup?: ReplyMarkup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to clear draft after sending this message.
|
||||||
|
*
|
||||||
|
* Defaults to `false`
|
||||||
|
*/
|
||||||
|
clearDraft?: boolean
|
||||||
}
|
}
|
||||||
): Promise<Message> {
|
): Promise<Message> {
|
||||||
return sendText.apply(this, arguments)
|
return sendText.apply(this, arguments)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
Chat,
|
Chat,
|
||||||
ChatPreview,
|
ChatPreview,
|
||||||
ChatMember,
|
ChatMember,
|
||||||
|
Dialog,
|
||||||
InputChatPermissions,
|
InputChatPermissions,
|
||||||
TermsOfService,
|
TermsOfService,
|
||||||
SentCode,
|
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
|
* @param total Total file size
|
||||||
*/
|
*/
|
||||||
progressCallback?: (uploaded: number, total: number) => void
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to clear draft after sending this message.
|
||||||
|
*
|
||||||
|
* Defaults to `false`
|
||||||
|
*/
|
||||||
|
clearDraft?: boolean
|
||||||
}
|
}
|
||||||
): Promise<Message> {
|
): Promise<Message> {
|
||||||
if (!params) params = {}
|
if (!params) params = {}
|
||||||
|
@ -143,9 +150,10 @@ export async function sendMedia(
|
||||||
w: media.width || 0,
|
w: media.width || 0,
|
||||||
h: media.height || 0,
|
h: media.height || 0,
|
||||||
supportsStreaming: media.supportsStreaming,
|
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') {
|
if (media.type === 'audio' || media.type === 'voice') {
|
||||||
|
@ -155,7 +163,7 @@ export async function sendMedia(
|
||||||
duration: media.duration || 0,
|
duration: media.duration || 0,
|
||||||
title: media.type === 'audio' ? media.title : undefined,
|
title: media.type === 'audio' ? media.title : undefined,
|
||||||
performer: media.type === 'audio' ? media.performer : 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,
|
file: inputFile,
|
||||||
thumb,
|
thumb,
|
||||||
mimeType: mime,
|
mimeType: mime,
|
||||||
attributes
|
attributes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +187,6 @@ export async function sendMedia(
|
||||||
const peer = normalizeToInputPeer(await this.resolvePeer(chatId))
|
const peer = normalizeToInputPeer(await this.resolvePeer(chatId))
|
||||||
const replyMarkup = BotKeyboard._convertToTl(params.replyMarkup)
|
const replyMarkup = BotKeyboard._convertToTl(params.replyMarkup)
|
||||||
|
|
||||||
|
|
||||||
const res = await this.call({
|
const res = await this.call({
|
||||||
_: 'messages.sendMedia',
|
_: 'messages.sendMedia',
|
||||||
peer,
|
peer,
|
||||||
|
@ -195,6 +202,7 @@ export async function sendMedia(
|
||||||
replyMarkup,
|
replyMarkup,
|
||||||
message,
|
message,
|
||||||
entities,
|
entities,
|
||||||
|
clearDraft: params.clearDraft,
|
||||||
})
|
})
|
||||||
|
|
||||||
return this._findMessageInUpdate(res)
|
return this._findMessageInUpdate(res)
|
||||||
|
|
|
@ -82,6 +82,13 @@ export async function sendPhoto(
|
||||||
* @param total Total file size
|
* @param total Total file size
|
||||||
*/
|
*/
|
||||||
progressCallback?: (uploaded: number, total: number) => void
|
progressCallback?: (uploaded: number, total: number) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to clear draft after sending this message.
|
||||||
|
*
|
||||||
|
* Defaults to `false`
|
||||||
|
*/
|
||||||
|
clearDraft?: boolean
|
||||||
}
|
}
|
||||||
): Promise<Message> {
|
): Promise<Message> {
|
||||||
if (!params) params = {}
|
if (!params) params = {}
|
||||||
|
@ -141,6 +148,7 @@ export async function sendPhoto(
|
||||||
replyMarkup,
|
replyMarkup,
|
||||||
message,
|
message,
|
||||||
entities,
|
entities,
|
||||||
|
clearDraft: params.clearDraft,
|
||||||
})
|
})
|
||||||
|
|
||||||
return this._findMessageInUpdate(res)
|
return this._findMessageInUpdate(res)
|
||||||
|
|
|
@ -2,12 +2,7 @@ import { TelegramClient } from '../../client'
|
||||||
import { tl } from '@mtcute/tl'
|
import { tl } from '@mtcute/tl'
|
||||||
import { inputPeerToPeer, normalizeToInputPeer } from '../../utils/peer-utils'
|
import { inputPeerToPeer, normalizeToInputPeer } from '../../utils/peer-utils'
|
||||||
import { normalizeDate, randomUlong } from '../../utils/misc-utils'
|
import { normalizeDate, randomUlong } from '../../utils/misc-utils'
|
||||||
import {
|
import { InputPeerLike, Message, BotKeyboard, ReplyMarkup } from '../../types'
|
||||||
InputPeerLike,
|
|
||||||
Message,
|
|
||||||
BotKeyboard,
|
|
||||||
ReplyMarkup,
|
|
||||||
} from '../../types'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a text message
|
* Send a text message
|
||||||
|
@ -64,6 +59,13 @@ export async function sendText(
|
||||||
* to hide a reply keyboard or to force a reply.
|
* to hide a reply keyboard or to force a reply.
|
||||||
*/
|
*/
|
||||||
replyMarkup?: ReplyMarkup
|
replyMarkup?: ReplyMarkup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to clear draft after sending this message.
|
||||||
|
*
|
||||||
|
* Defaults to `false`
|
||||||
|
*/
|
||||||
|
clearDraft?: boolean
|
||||||
}
|
}
|
||||||
): Promise<Message> {
|
): Promise<Message> {
|
||||||
if (!params) params = {}
|
if (!params) params = {}
|
||||||
|
@ -92,6 +94,7 @@ export async function sendText(
|
||||||
replyMarkup,
|
replyMarkup,
|
||||||
message,
|
message,
|
||||||
entities,
|
entities,
|
||||||
|
clearDraft: params.clearDraft,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res._ === 'updateShortSentMessage') {
|
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-entity'
|
||||||
export * from './message'
|
export * from './message'
|
||||||
export * from './search-filters'
|
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!
|
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
|
* Title, for supergroups, channels and groups
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue