feat: user status and typing related methods and updates
This commit is contained in:
parent
8a0c9984b5
commit
002d949a13
11 changed files with 551 additions and 24 deletions
|
@ -73,6 +73,7 @@ import { _parseEntities } from './methods/messages/parse-entities'
|
|||
import { pinMessage } from './methods/messages/pin-message'
|
||||
import { searchGlobal } from './methods/messages/search-global'
|
||||
import { searchMessages } from './methods/messages/search-messages'
|
||||
import { sendTyping } from './methods/messages/send-chat-action'
|
||||
import { sendMediaGroup } from './methods/messages/send-media-group'
|
||||
import { sendMedia } from './methods/messages/send-media'
|
||||
import { sendText } from './methods/messages/send-text'
|
||||
|
@ -105,6 +106,7 @@ import { getCommonChats } from './methods/users/get-common-chats'
|
|||
import { getMe } from './methods/users/get-me'
|
||||
import { getUsers } from './methods/users/get-users'
|
||||
import { resolvePeer } from './methods/users/resolve-peer'
|
||||
import { setOffline } from './methods/users/set-offline'
|
||||
import { IMessageEntityParser } from './parser'
|
||||
import { Readable } from 'stream'
|
||||
import {
|
||||
|
@ -1673,6 +1675,50 @@ export interface TelegramClient extends BaseTelegramClient {
|
|||
chunkSize?: number
|
||||
}
|
||||
): AsyncIterableIterator<Message>
|
||||
/**
|
||||
* Sends a current user/bot typing event
|
||||
* to a conversation partner or group.
|
||||
*
|
||||
* This status is set for 6 seconds, and is
|
||||
* automatically cancelled if you send a
|
||||
* message.
|
||||
*
|
||||
* @param chatId Chat ID
|
||||
* @param action
|
||||
* (default: `'typing'`)
|
||||
* Chat action:
|
||||
* - `typing` - user is typing
|
||||
* - `cancel` to cancel previously sent event
|
||||
* - `record_video` - user is recording a video
|
||||
* - `upload_video` - user is uploading a video
|
||||
* - `record_voice` - user is recording a voice note
|
||||
* - `upload_voice` - user is uploading a voice note
|
||||
* - `upload_photo` - user is uploading a photo
|
||||
* - `upload_document` - user is sending a document
|
||||
*
|
||||
* @param progress For `upload_*` actions, progress of the upload (optional)
|
||||
*/
|
||||
sendChatAction(
|
||||
chatId: InputPeerLike,
|
||||
action?:
|
||||
| 'typing'
|
||||
| 'cancel'
|
||||
| 'record_video'
|
||||
| 'upload_video'
|
||||
| 'record_voice'
|
||||
| 'upload_voice'
|
||||
| 'upload_photo'
|
||||
| 'upload_document'
|
||||
| 'geo'
|
||||
| 'contact'
|
||||
| 'game'
|
||||
| 'record_round'
|
||||
| 'upload_round'
|
||||
| 'group_call'
|
||||
| 'history_import'
|
||||
| tl.TypeSendMessageAction,
|
||||
progress?: number
|
||||
): Promise<void>
|
||||
/**
|
||||
* Send a group of media.
|
||||
*
|
||||
|
@ -2169,6 +2215,12 @@ export interface TelegramClient extends BaseTelegramClient {
|
|||
resolvePeer(
|
||||
peerId: InputPeerLike
|
||||
): Promise<tl.TypeInputPeer | tl.TypeInputUser | tl.TypeInputChannel>
|
||||
/**
|
||||
* Change user status to offline or online
|
||||
*
|
||||
* @param offline (default: `true`) Whether the user is currently offline
|
||||
*/
|
||||
setOffline(offline?: boolean): Promise<void>
|
||||
}
|
||||
/** @internal */
|
||||
export class TelegramClient extends BaseTelegramClient {
|
||||
|
@ -2273,6 +2325,7 @@ export class TelegramClient extends BaseTelegramClient {
|
|||
pinMessage = pinMessage
|
||||
searchGlobal = searchGlobal
|
||||
searchMessages = searchMessages
|
||||
sendChatAction = sendTyping
|
||||
sendMediaGroup = sendMediaGroup
|
||||
sendMedia = sendMedia
|
||||
sendText = sendText
|
||||
|
@ -2301,4 +2354,5 @@ export class TelegramClient extends BaseTelegramClient {
|
|||
getMe = getMe
|
||||
getUsers = getUsers
|
||||
resolvePeer = resolvePeer
|
||||
setOffline = setOffline
|
||||
}
|
||||
|
|
81
packages/client/src/methods/messages/send-typing.ts
Normal file
81
packages/client/src/methods/messages/send-typing.ts
Normal file
|
@ -0,0 +1,81 @@
|
|||
import { TelegramClient } from '../../client'
|
||||
import { tl } from '@mtcute/tl'
|
||||
import { InputPeerLike } from '../../types'
|
||||
import { TypingStatus } from '../../types/peers/typing-status'
|
||||
import { normalizeToInputPeer } from '../../utils/peer-utils'
|
||||
|
||||
/**
|
||||
* Sends a current user/bot typing event
|
||||
* to a conversation partner or group.
|
||||
*
|
||||
* This status is set for 6 seconds, and is
|
||||
* automatically cancelled if you send a
|
||||
* message.
|
||||
*
|
||||
* @param chatId Chat ID
|
||||
* @param status Typing status
|
||||
* @param progress For `upload_*` and actions, progress of the upload
|
||||
* @internal
|
||||
*/
|
||||
export async function sendTyping(
|
||||
this: TelegramClient,
|
||||
chatId: InputPeerLike,
|
||||
status: TypingStatus | tl.TypeSendMessageAction = 'typing',
|
||||
progress = 0
|
||||
): Promise<void> {
|
||||
if (typeof status === 'string') {
|
||||
switch (status) {
|
||||
case 'typing':
|
||||
status = { _: 'sendMessageTypingAction' }
|
||||
break;
|
||||
case 'cancel':
|
||||
status = { _: 'sendMessageCancelAction' }
|
||||
break;
|
||||
case 'record_video':
|
||||
status = { _: 'sendMessageRecordVideoAction' }
|
||||
break;
|
||||
case 'upload_video':
|
||||
status = { _: 'sendMessageUploadVideoAction', progress }
|
||||
break;
|
||||
case 'record_voice':
|
||||
status = { _: 'sendMessageRecordAudioAction' }
|
||||
break;
|
||||
case 'upload_voice':
|
||||
status = { _: 'sendMessageUploadAudioAction', progress }
|
||||
break;
|
||||
case 'upload_photo':
|
||||
status = { _: 'sendMessageUploadPhotoAction', progress }
|
||||
break;
|
||||
case 'upload_document':
|
||||
status = { _: 'sendMessageUploadDocumentAction', progress }
|
||||
break;
|
||||
case 'geo':
|
||||
status = { _: 'sendMessageGeoLocationAction' }
|
||||
break;
|
||||
case 'contact':
|
||||
status = { _: 'sendMessageChooseContactAction' }
|
||||
break;
|
||||
case 'game':
|
||||
status = { _: 'sendMessageGamePlayAction' }
|
||||
break;
|
||||
case 'record_round':
|
||||
status = { _: 'sendMessageRecordRoundAction' }
|
||||
break;
|
||||
case 'upload_round':
|
||||
status = { _: 'sendMessageUploadRoundAction', progress }
|
||||
break;
|
||||
case 'speak_call':
|
||||
status = { _: 'speakingInGroupCallAction' }
|
||||
break;
|
||||
case 'history_import':
|
||||
status = { _: 'sendMessageHistoryImportAction', progress }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
await this.call({
|
||||
_: 'messages.setTyping',
|
||||
peer: normalizeToInputPeer(await this.resolvePeer(chatId)),
|
||||
action: status
|
||||
})
|
||||
}
|
17
packages/client/src/methods/users/set-offline.ts
Normal file
17
packages/client/src/methods/users/set-offline.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { TelegramClient } from '../../client'
|
||||
|
||||
/**
|
||||
* Change user status to offline or online
|
||||
*
|
||||
* @param offline Whether the user is currently offline
|
||||
* @internal
|
||||
*/
|
||||
export async function setOffline(
|
||||
this: TelegramClient,
|
||||
offline = true
|
||||
): Promise<void> {
|
||||
await this.call({
|
||||
_: 'account.updateStatus',
|
||||
offline
|
||||
})
|
||||
}
|
38
packages/client/src/types/peers/typing-status.ts
Normal file
38
packages/client/src/types/peers/typing-status.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* User typing status. Used to provide detailed
|
||||
* information about chat partners' actions:
|
||||
* typing messages, recording/uploading attachments, etc.
|
||||
*
|
||||
* Can be:
|
||||
* - `typing`: User is typing
|
||||
* - `cancel`: User is not doing anything (used to cancel previously sent status)
|
||||
* - `record_video`: User is recording a video
|
||||
* - `upload_video`: User is uploading a video
|
||||
* - `record_voice`: User is recording a voice message
|
||||
* - `upload_voice`: User is uploading a voice message
|
||||
* - `upload_photo`: User is uploading a photo
|
||||
* - `upload_document`: User is uploading a document
|
||||
* - `geo`: User is choosing a geolocation to share
|
||||
* - `contact`: User is choosing a contact to share
|
||||
* - `game`: User is playing a game
|
||||
* - `record_round`: User is recording a round video message
|
||||
* - `upload_round`: User is uploading a round video message
|
||||
* - `speak_call`: *undocumented* User is speaking in a group call
|
||||
* - `history_import`: *undocumented* User is importing history
|
||||
*/
|
||||
export type TypingStatus =
|
||||
| 'typing'
|
||||
| 'cancel'
|
||||
| 'record_video'
|
||||
| 'upload_video'
|
||||
| 'record_voice'
|
||||
| 'upload_voice'
|
||||
| 'upload_photo'
|
||||
| 'upload_document'
|
||||
| 'geo'
|
||||
| 'contact'
|
||||
| 'game'
|
||||
| 'record_round'
|
||||
| 'upload_round'
|
||||
| 'speak_call'
|
||||
| 'history_import'
|
|
@ -25,12 +25,12 @@ export namespace User {
|
|||
| 'within_month'
|
||||
| 'long_time_ago'
|
||||
| 'bot'
|
||||
}
|
||||
|
||||
interface ParsedStatus {
|
||||
status: User.Status
|
||||
lastOnline: Date | null
|
||||
nextOffline: Date | null
|
||||
export interface ParsedStatus {
|
||||
status: User.Status
|
||||
lastOnline: Date | null
|
||||
nextOffline: Date | null
|
||||
}
|
||||
}
|
||||
|
||||
export class User {
|
||||
|
@ -117,40 +117,43 @@ export class User {
|
|||
return this._user.lastName ?? null
|
||||
}
|
||||
|
||||
private _parsedStatus?: ParsedStatus
|
||||
|
||||
private _parseStatus() {
|
||||
let status: User.Status
|
||||
static parseStatus(status: tl.TypeUserStatus, bot = false): User.ParsedStatus {
|
||||
let ret: User.Status
|
||||
let date: Date
|
||||
|
||||
const us = this._user.status
|
||||
const us = status
|
||||
if (!us) {
|
||||
status = 'long_time_ago'
|
||||
} else if (this._user.bot) {
|
||||
status = 'bot'
|
||||
ret = 'long_time_ago'
|
||||
} else if (bot) {
|
||||
ret = 'bot'
|
||||
} else if (us._ === 'userStatusOnline') {
|
||||
status = 'online'
|
||||
ret = 'online'
|
||||
date = new Date(us.expires * 1000)
|
||||
} else if (us._ === 'userStatusOffline') {
|
||||
status = 'offline'
|
||||
ret = 'offline'
|
||||
date = new Date(us.wasOnline * 1000)
|
||||
} else if (us._ === 'userStatusRecently') {
|
||||
status = 'recently'
|
||||
ret = 'recently'
|
||||
} else if (us._ === 'userStatusLastWeek') {
|
||||
status = 'within_week'
|
||||
ret = 'within_week'
|
||||
} else if (us._ === 'userStatusLastMonth') {
|
||||
status = 'within_month'
|
||||
ret = 'within_month'
|
||||
} else {
|
||||
status = 'long_time_ago'
|
||||
ret = 'long_time_ago'
|
||||
}
|
||||
|
||||
this._parsedStatus = {
|
||||
status,
|
||||
lastOnline: status === 'offline' ? date! : null,
|
||||
nextOffline: status === 'online' ? date! : null,
|
||||
return {
|
||||
status: ret,
|
||||
lastOnline: ret === 'offline' ? date! : null,
|
||||
nextOffline: ret === 'online' ? date! : null,
|
||||
}
|
||||
}
|
||||
|
||||
private _parsedStatus?: User.ParsedStatus
|
||||
private _parseStatus() {
|
||||
this._parsedStatus = User.parseStatus(this._user.status!, this._user.bot)
|
||||
}
|
||||
|
||||
/** User's Last Seen & Online status */
|
||||
get status(): User.Status {
|
||||
if (!this._parsedStatus) this._parseStatus()
|
||||
|
|
|
@ -9,3 +9,5 @@ chosen_inline_result = ChosenInlineResult
|
|||
callback_query = CallbackQuery
|
||||
poll: PollUpdate = PollUpdate
|
||||
poll_vote = PollVoteUpdate
|
||||
user_status: UserStatusUpdate = UserStatusUpdate
|
||||
user_typing = UserTypingUpdate
|
||||
|
|
|
@ -10,6 +10,8 @@ import {
|
|||
CallbackQueryHandler,
|
||||
PollUpdateHandler,
|
||||
PollVoteHandler,
|
||||
UserStatusUpdateHandler,
|
||||
UserTypingHandler,
|
||||
} from './handler'
|
||||
// end-codegen-imports
|
||||
import { filters, UpdateFilter } from './filters'
|
||||
|
@ -18,6 +20,8 @@ import { ChatMemberUpdate } from './updates'
|
|||
import { ChosenInlineResult } from './updates/chosen-inline-result'
|
||||
import { PollUpdate } from './updates/poll-update'
|
||||
import { PollVoteUpdate } from './updates/poll-vote'
|
||||
import { UserStatusUpdate } from './updates/user-status-update'
|
||||
import { UserTypingUpdate } from './updates/user-typing-update'
|
||||
|
||||
function _create<T extends UpdateHandler>(
|
||||
type: T['type'],
|
||||
|
@ -291,5 +295,62 @@ export namespace handlers {
|
|||
return _create('poll_vote', filter, handler)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an user status update handler
|
||||
*
|
||||
* @param handler User status update handler
|
||||
*/
|
||||
export function userStatusUpdate(
|
||||
handler: UserStatusUpdateHandler['callback']
|
||||
): UserStatusUpdateHandler
|
||||
|
||||
/**
|
||||
* Create an user status update handler with a filter
|
||||
*
|
||||
* @param filter Update filter
|
||||
* @param handler User status update handler
|
||||
*/
|
||||
export function userStatusUpdate<Mod>(
|
||||
filter: UpdateFilter<UserStatusUpdate, Mod>,
|
||||
handler: UserStatusUpdateHandler<
|
||||
filters.Modify<UserStatusUpdate, Mod>
|
||||
>['callback']
|
||||
): UserStatusUpdateHandler
|
||||
|
||||
/** @internal */
|
||||
export function userStatusUpdate(
|
||||
filter: any,
|
||||
handler?: any
|
||||
): UserStatusUpdateHandler {
|
||||
return _create('user_status', filter, handler)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an user typing handler
|
||||
*
|
||||
* @param handler User typing handler
|
||||
*/
|
||||
export function userTyping(
|
||||
handler: UserTypingHandler['callback']
|
||||
): UserTypingHandler
|
||||
|
||||
/**
|
||||
* Create an user typing handler with a filter
|
||||
*
|
||||
* @param filter Update filter
|
||||
* @param handler User typing handler
|
||||
*/
|
||||
export function userTyping<Mod>(
|
||||
filter: UpdateFilter<UserTypingUpdate, Mod>,
|
||||
handler: UserTypingHandler<
|
||||
filters.Modify<UserTypingUpdate, Mod>
|
||||
>['callback']
|
||||
): UserTypingHandler
|
||||
|
||||
/** @internal */
|
||||
export function userTyping(filter: any, handler?: any): UserTypingHandler {
|
||||
return _create('user_typing', filter, handler)
|
||||
}
|
||||
|
||||
// end-codegen
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ import {
|
|||
CallbackQueryHandler,
|
||||
PollUpdateHandler,
|
||||
PollVoteHandler,
|
||||
UserStatusUpdateHandler,
|
||||
UserTypingHandler,
|
||||
} from './handler'
|
||||
// end-codegen-imports
|
||||
import { filters, UpdateFilter } from './filters'
|
||||
|
@ -32,6 +34,8 @@ import { ChatMemberUpdate } from './updates'
|
|||
import { ChosenInlineResult } from './updates/chosen-inline-result'
|
||||
import { PollUpdate } from './updates/poll-update'
|
||||
import { PollVoteUpdate } from './updates/poll-vote'
|
||||
import { UserStatusUpdate } from './updates/user-status-update'
|
||||
import { UserTypingUpdate } from './updates/user-typing-update'
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
|
@ -67,6 +71,10 @@ const callbackQueryParser: UpdateParser = [
|
|||
'callback_query',
|
||||
(client, upd, users) => new CallbackQuery(client, upd as any, users),
|
||||
]
|
||||
const userTypingParser: UpdateParser = [
|
||||
'user_typing',
|
||||
(client, upd) => new UserTypingUpdate(client, upd as any)
|
||||
]
|
||||
|
||||
const PARSERS: Partial<
|
||||
Record<(tl.TypeUpdate | tl.TypeMessage)['_'], UpdateParser>
|
||||
|
@ -100,10 +108,17 @@ const PARSERS: Partial<
|
|||
'poll_vote',
|
||||
(client, upd, users) => new PollVoteUpdate(client, upd as any, users),
|
||||
],
|
||||
updateUserStatus: [
|
||||
'user_status',
|
||||
(client, upd) => new UserStatusUpdate(client, upd as any),
|
||||
],
|
||||
updateChannelUserTyping: userTypingParser,
|
||||
updateChatUserTyping: userTypingParser,
|
||||
updateUserTyping: userTypingParser,
|
||||
}
|
||||
|
||||
/**
|
||||
* The dispatcher
|
||||
* Updates dispatcher
|
||||
*/
|
||||
export class Dispatcher {
|
||||
private _groups: Record<number, UpdateHandler[]> = {}
|
||||
|
@ -667,5 +682,66 @@ export class Dispatcher {
|
|||
this._addKnownHandler('pollVote', filter, handler, group)
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an user status update handler without any filters
|
||||
*
|
||||
* @param handler User status update handler
|
||||
* @param group Handler group index
|
||||
* @internal
|
||||
*/
|
||||
onUserStatusUpdate(
|
||||
handler: UserStatusUpdateHandler['callback'],
|
||||
group?: number
|
||||
): void
|
||||
|
||||
/**
|
||||
* Register an user status update handler with a filter
|
||||
*
|
||||
* @param filter Update filter
|
||||
* @param handler User status update handler
|
||||
* @param group Handler group index
|
||||
*/
|
||||
onUserStatusUpdate<Mod>(
|
||||
filter: UpdateFilter<UserStatusUpdate, Mod>,
|
||||
handler: UserStatusUpdateHandler<
|
||||
filters.Modify<UserStatusUpdate, Mod>
|
||||
>['callback'],
|
||||
group?: number
|
||||
): void
|
||||
|
||||
/** @internal */
|
||||
onUserStatusUpdate(filter: any, handler?: any, group?: number): void {
|
||||
this._addKnownHandler('userStatusUpdate', filter, handler, group)
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an user typing handler without any filters
|
||||
*
|
||||
* @param handler User typing handler
|
||||
* @param group Handler group index
|
||||
* @internal
|
||||
*/
|
||||
onUserTyping(handler: UserTypingHandler['callback'], group?: number): void
|
||||
|
||||
/**
|
||||
* Register an user typing handler with a filter
|
||||
*
|
||||
* @param filter Update filter
|
||||
* @param handler User typing handler
|
||||
* @param group Handler group index
|
||||
*/
|
||||
onUserTyping<Mod>(
|
||||
filter: UpdateFilter<UserTypingUpdate, Mod>,
|
||||
handler: UserTypingHandler<
|
||||
filters.Modify<UserTypingUpdate, Mod>
|
||||
>['callback'],
|
||||
group?: number
|
||||
): void
|
||||
|
||||
/** @internal */
|
||||
onUserTyping(filter: any, handler?: any, group?: number): void {
|
||||
this._addKnownHandler('userTyping', filter, handler, group)
|
||||
}
|
||||
|
||||
// end-codegen
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import { ChatMemberUpdate } from './updates'
|
|||
import { ChosenInlineResult } from './updates/chosen-inline-result'
|
||||
import { PollUpdate } from './updates/poll-update'
|
||||
import { PollVoteUpdate } from './updates/poll-vote'
|
||||
import { UserStatusUpdate } from './updates/user-status-update'
|
||||
import { UserTypingUpdate } from './updates/user-typing-update'
|
||||
|
||||
interface BaseUpdateHandler<Type, Handler, Checker> {
|
||||
type: Type
|
||||
|
@ -73,6 +75,14 @@ export type PollVoteHandler<T = PollVoteUpdate> = ParsedUpdateHandler<
|
|||
'poll_vote',
|
||||
T
|
||||
>
|
||||
export type UserStatusUpdateHandler<T = UserStatusUpdate> = ParsedUpdateHandler<
|
||||
'user_status',
|
||||
T
|
||||
>
|
||||
export type UserTypingHandler<T = UserTypingUpdate> = ParsedUpdateHandler<
|
||||
'user_typing',
|
||||
T
|
||||
>
|
||||
|
||||
export type UpdateHandler =
|
||||
| RawUpdateHandler
|
||||
|
@ -84,5 +94,7 @@ export type UpdateHandler =
|
|||
| CallbackQueryHandler
|
||||
| PollUpdateHandler
|
||||
| PollVoteHandler
|
||||
| UserStatusUpdateHandler
|
||||
| UserTypingHandler
|
||||
|
||||
// end-codegen
|
||||
|
|
66
packages/dispatcher/src/updates/user-status-update.ts
Normal file
66
packages/dispatcher/src/updates/user-status-update.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
import { TelegramClient, User } from '@mtcute/client'
|
||||
import { tl } from '@mtcute/tl'
|
||||
import { makeInspectable } from '@mtcute/client/src/types/utils'
|
||||
|
||||
/**
|
||||
* User status has changed
|
||||
*/
|
||||
export class UserStatusUpdate {
|
||||
readonly client: TelegramClient
|
||||
readonly raw: tl.RawUpdateUserStatus
|
||||
|
||||
constructor(
|
||||
client: TelegramClient,
|
||||
raw: tl.RawUpdateUserStatus
|
||||
) {
|
||||
this.client = client
|
||||
this.raw = raw
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the user whose status has updated
|
||||
*/
|
||||
get userId(): number {
|
||||
return this.raw.userId
|
||||
}
|
||||
|
||||
private _parsedStatus?: User.ParsedStatus
|
||||
private _parseStatus() {
|
||||
this._parsedStatus = User.parseStatus(this.raw.status)
|
||||
}
|
||||
|
||||
/**
|
||||
* User's new Last Seen & Online status
|
||||
*/
|
||||
get status(): User.Status {
|
||||
if (!this._parsedStatus) this._parseStatus()
|
||||
return this._parsedStatus!.status
|
||||
}
|
||||
|
||||
/**
|
||||
* Last time this user was seen online.
|
||||
* Only available if {@link status} is `offline`
|
||||
*/
|
||||
get lastOnline(): Date | null {
|
||||
if (!this._parsedStatus) this._parseStatus()
|
||||
return this._parsedStatus!.lastOnline
|
||||
}
|
||||
|
||||
/**
|
||||
* Time when this user will automatically go offline.
|
||||
* Only available if {@link status} is `online`
|
||||
*/
|
||||
get nextOffline(): Date | null {
|
||||
if (!this._parsedStatus) this._parseStatus()
|
||||
return this._parsedStatus!.nextOffline
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch information about the user
|
||||
*/
|
||||
getUser(): Promise<User> {
|
||||
return this.client.getUsers(this.raw.userId)
|
||||
}
|
||||
}
|
||||
|
||||
makeInspectable(UserStatusUpdate)
|
117
packages/dispatcher/src/updates/user-typing-update.ts
Normal file
117
packages/dispatcher/src/updates/user-typing-update.ts
Normal file
|
@ -0,0 +1,117 @@
|
|||
import { BasicPeerType, Chat, MtCuteUnsupportedError, TelegramClient, User } from '@mtcute/client'
|
||||
import { tl } from '@mtcute/tl'
|
||||
import { getBarePeerId, MAX_CHANNEL_ID } from '@mtcute/core'
|
||||
import { TypingStatus } from '@mtcute/client/src/types/peers/typing-status'
|
||||
import { makeInspectable } from '@mtcute/client/src/types/utils'
|
||||
|
||||
/**
|
||||
* User's typing status has changed.
|
||||
*
|
||||
* This update is valid for 6 seconds.
|
||||
*/
|
||||
export class UserTypingUpdate {
|
||||
readonly client: TelegramClient
|
||||
readonly raw:
|
||||
| tl.RawUpdateUserTyping
|
||||
| tl.RawUpdateChatUserTyping
|
||||
| tl.RawUpdateChannelUserTyping
|
||||
|
||||
constructor(client: TelegramClient, raw: UserTypingUpdate['raw']) {
|
||||
this.client = client
|
||||
this.raw = raw
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the user whose typing status changed
|
||||
*/
|
||||
get userId(): number {
|
||||
return this.raw._ === 'updateUserTyping'
|
||||
? this.raw.userId
|
||||
: getBarePeerId(this.raw.fromId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Marked ID of the chat where the user is typing,
|
||||
*
|
||||
* If the user is typing in PMs, this will
|
||||
* equal to {@link userId}
|
||||
*/
|
||||
get chatId(): number {
|
||||
switch (this.raw._) {
|
||||
case 'updateUserTyping':
|
||||
return this.raw.userId
|
||||
case 'updateChatUserTyping':
|
||||
return -this.raw.chatId
|
||||
case 'updateChannelUserTyping':
|
||||
return MAX_CHANNEL_ID - this.raw.channelId
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of the chat where this event has occurred
|
||||
*/
|
||||
get chatType(): BasicPeerType {
|
||||
switch (this.raw._) {
|
||||
case 'updateUserTyping':
|
||||
return 'user'
|
||||
case 'updateChatUserTyping':
|
||||
return 'chat'
|
||||
case 'updateChannelUserTyping':
|
||||
return 'channel'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Current typing status
|
||||
*/
|
||||
get status(): TypingStatus {
|
||||
switch (this.raw.action._) {
|
||||
case 'sendMessageTypingAction':
|
||||
return 'typing'
|
||||
case 'sendMessageCancelAction':
|
||||
return 'cancel'
|
||||
case 'sendMessageRecordVideoAction':
|
||||
return 'record_video'
|
||||
case 'sendMessageUploadVideoAction':
|
||||
return 'upload_video'
|
||||
case 'sendMessageRecordAudioAction':
|
||||
return 'record_voice'
|
||||
case 'sendMessageUploadAudioAction':
|
||||
return 'upload_voice'
|
||||
case 'sendMessageUploadPhotoAction':
|
||||
return 'upload_photo'
|
||||
case 'sendMessageUploadDocumentAction':
|
||||
return 'upload_document'
|
||||
case 'sendMessageGeoLocationAction':
|
||||
return 'geo'
|
||||
case 'sendMessageChooseContactAction':
|
||||
return 'contact'
|
||||
case 'sendMessageRecordRoundAction':
|
||||
return 'record_round'
|
||||
case 'sendMessageUploadRoundAction':
|
||||
return 'upload_round'
|
||||
case 'speakingInGroupCallAction':
|
||||
return 'speak_call'
|
||||
case 'sendMessageHistoryImportAction':
|
||||
return 'history_import'
|
||||
}
|
||||
|
||||
throw new MtCuteUnsupportedError()
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the user whose typing status has changed
|
||||
*/
|
||||
getUser(): Promise<User> {
|
||||
return this.client.getUsers(this.userId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the chat where the update has happenned
|
||||
*/
|
||||
getChat(): Promise<Chat> {
|
||||
return this.client.getChat(this.chatId)
|
||||
}
|
||||
}
|
||||
|
||||
makeInspectable(UserTypingUpdate)
|
Loading…
Reference in a new issue