This commit is contained in:
teidesu 2021-06-12 01:13:02 +03:00
parent 46317e8ddb
commit 707e317e16
5 changed files with 222 additions and 14 deletions

View file

@ -263,6 +263,20 @@ export namespace BotKeyboard {
return { _: 'keyboardButtonGame', text } return { _: 'keyboardButtonGame', text }
} }
/**
* Button to pay for a product.
*
* Used for inline keyboards, not reply!
*
* **Note**: This type of button must always be
* the first button in the first row. Related
* invoice is inferred from {@link InputMedia.invoice},
* thus this button should only be used with it.
*/
export function pay(text: string): tl.RawKeyboardButtonBuy {
return { _: 'keyboardButtonBuy', text }
}
/** /**
* Button to authorize a user * Button to authorize a user
* *
@ -309,6 +323,34 @@ export namespace BotKeyboard {
} }
} }
/**
* Find a button in the keyboard by its text or by predicate
*
* @param buttons Two-dimensional array of buttons
* @param predicate Button text or predicate function
*/
export function findButton(
buttons: tl.TypeKeyboardButton[][],
predicate: string | ((btn: tl.TypeKeyboardButton) => boolean)
): tl.TypeKeyboardButton | null {
if (typeof predicate === 'string') {
const text = predicate
predicate = (btn) => {
return 'text' in btn && btn.text === text
}
}
for (const row of buttons) {
for (const btn of row) {
if (predicate(btn)) {
return btn
}
}
}
return null
}
/** @internal */ /** @internal */
export function _rowsTo2d( export function _rowsTo2d(
rows: tl.RawKeyboardButtonRow[] rows: tl.RawKeyboardButtonRow[]

View file

@ -7,6 +7,7 @@ import { MtCuteArgumentError, MtCuteTypeAssertionError } from '../errors'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
import { ChatsIndex, InputPeerLike, User, UsersIndex } from './index' import { ChatsIndex, InputPeerLike, User, UsersIndex } from './index'
import { ChatLocation } from './chat-location' import { ChatLocation } from './chat-location'
import { InputMediaLike } from '../media'
export namespace Chat { export namespace Chat {
/** /**
@ -559,6 +560,32 @@ export class Chat {
async readHistory(message = 0, clearMentions = false): Promise<void> { async readHistory(message = 0, clearMentions = false): Promise<void> {
return this.client.readHistory(this.inputPeer, message, clearMentions) return this.client.readHistory(this.inputPeer, message, clearMentions)
} }
/**
* Send a text message in this chat.
*
* @param text Text of the message
* @param params
*/
sendText(
text: string,
params?: Parameters<TelegramClient['sendText']>[2]
): ReturnType<TelegramClient['sendText']> {
return this.client.sendText(this.inputPeer, text, params)
}
/**
* Send a media in this chat.
*
* @param media Media to send
* @param params
*/
sendMedia(
media: InputMediaLike,
params?: Parameters<TelegramClient['sendText']>[2]
): ReturnType<TelegramClient['sendText']> {
return this.client.sendMedia(this.inputPeer, media, params)
}
} }
makeInspectable(Chat, [], ['user']) makeInspectable(Chat, [], ['user'])

View file

@ -4,6 +4,7 @@ import { ChatPhoto } from './chat-photo'
import { MtCuteArgumentError } from '../errors' import { MtCuteArgumentError } from '../errors'
import { makeInspectable } from '../utils' import { makeInspectable } from '../utils'
import { assertTypeIs } from '../../utils/type-assertion' import { assertTypeIs } from '../../utils/type-assertion'
import { InputMediaLike } from '../media'
export namespace User { export namespace User {
/** /**
@ -356,6 +357,32 @@ export class User {
}, },
]) ])
} }
/**
* Send a text message to this user.
*
* @param text Text of the message
* @param params
*/
sendText(
text: string,
params?: Parameters<TelegramClient['sendText']>[2]
): ReturnType<TelegramClient['sendText']> {
return this.client.sendText(this.inputPeer, text, params)
}
/**
* Send a media to this user.
*
* @param media Media to send
* @param params
*/
sendMedia(
media: InputMediaLike,
params?: Parameters<TelegramClient['sendText']>[2]
): ReturnType<TelegramClient['sendText']> {
return this.client.sendMedia(this.inputPeer, media, params)
}
} }
makeInspectable(User) makeInspectable(User)

View file

@ -27,6 +27,9 @@ import { ChatMemberUpdate } from './updates'
import { ChosenInlineResult } from './updates/chosen-inline-result' import { ChosenInlineResult } from './updates/chosen-inline-result'
import { MessageAction } from '@mtcute/client/src/types/messages/message-action' import { MessageAction } from '@mtcute/client/src/types/messages/message-action'
import { UpdateState } from './state' import { UpdateState } from './state'
import { UserStatusUpdate } from './updates/user-status-update'
import { PollVoteUpdate } from './updates/poll-vote'
import { UserTypingUpdate } from './updates/user-typing-update'
/** /**
* Type describing a primitive filter, which is a function taking some `Base` * Type describing a primitive filter, which is a function taking some `Base`
@ -332,19 +335,97 @@ export namespace filters {
*/ */
export const chat = <T extends Chat.Type>( export const chat = <T extends Chat.Type>(
type: T type: T
): UpdateFilter<Message, { ): UpdateFilter<
chat: Modify<Chat, { type: T }> Message,
sender: T extends 'private' | 'bot' | 'group' ? User : User | Chat {
}> => (msg) => chat: Modify<Chat, { type: T }>
msg.chat.type === type sender: T extends 'private' | 'bot' | 'group' ? User : User | Chat
}
> => (msg) => msg.chat.type === type
/** /**
* Filter messages by chat ID * Filter updates by chat ID(s)
*/ */
export const chatId = ( export const chatId = (id: MaybeArray<number>): UpdateFilter<Message> => {
id: number if (Array.isArray(id)) {
): UpdateFilter<Message> => (msg) => const index: Record<number, true> = {}
msg.chat.id === id id.forEach((id) => (index[id] = true))
return (msg) => msg.chat.id in index
}
return (msg) => msg.chat.id === id
}
/**
* Filter updates by user ID(s)
*
* For chat member updates, uses `user.id`
*/
export const userId = (
id: MaybeArray<number>
): UpdateFilter<
| Message
| InlineQuery
| ChatMemberUpdate
| ChosenInlineResult
| CallbackQuery
| PollVoteUpdate
| UserStatusUpdate
| UserTypingUpdate
> => {
if (Array.isArray(id)) {
const index: Record<number, true> = {}
id.forEach((id) => (index[id] = true))
return (upd) => {
const ctor = upd.constructor
if (ctor === Message) {
return (upd as Message).sender.id in index
} else {
if (
ctor === UserStatusUpdate ||
ctor === UserTypingUpdate
) {
return (
(upd as UserStatusUpdate | UserTypingUpdate)
.userId in index
)
} else {
return (
(upd as Exclude<
typeof upd,
Message | UserStatusUpdate | UserTypingUpdate
>).user.id in index
)
}
}
}
}
return (upd) => {
const ctor = upd.constructor
if (ctor === Message) {
return (upd as Message).sender.id === id
} else {
if (ctor === UserStatusUpdate || ctor === UserTypingUpdate) {
return (
(upd as UserStatusUpdate | UserTypingUpdate).userId ===
id
)
} else {
return (
(upd as Exclude<
typeof upd,
Message | UserStatusUpdate | UserTypingUpdate
>).user.id === id
)
}
}
}
}
/** /**
* Filter incoming messages. * Filter incoming messages.
@ -702,6 +783,36 @@ export namespace filters {
return (upd) => upd.type === types return (upd) => upd.type === types
} }
/**
* Create a filter for {@link UserStatusUpdate} by new user status
*
* @param statuses Update type(s)
* @link User.Status
*/
export const userStatus: {
<T extends User.Status>(status: T): UpdateFilter<
UserStatusUpdate,
{
type: T
lastOnline: T extends 'offline' ? Date : null
nextOffline: T extends 'online' ? Date : null
}
>
<T extends User.Status[]>(statuses: T): UpdateFilter<
UserStatusUpdate,
{ type: T[number] }
>
} = (statuses: MaybeArray<User.Status>): UpdateFilter<UserStatusUpdate> => {
if (Array.isArray(statuses)) {
const index: Partial<Record<User.Status, true>> = {}
statuses.forEach((typ) => (index[typ] = true))
return (upd) => upd.status in index
}
return (upd) => upd.status === statuses
}
/** /**
* Create a filter for {@link ChatMemberUpdate} for updates * Create a filter for {@link ChatMemberUpdate} for updates
* regarding current user * regarding current user

View file

@ -27,7 +27,8 @@ export const ContinuePropagation: unique symbol = _sym.for(
'mtcute:ContinuePropagation' 'mtcute:ContinuePropagation'
) )
export type PropagationSymbol = export type PropagationSymbol = symbol
| typeof StopPropagation // this seems to cause issues after publishing
| typeof ContinuePropagation // | typeof StopPropagation
| typeof StopChildrenPropagation // | typeof ContinuePropagation
// | typeof StopChildrenPropagation