telega/dialog/render
The edit-or-send engine behind dialogs.
Keeps one live dialog message per chat: sends it the first time, edits it on every subsequent render. Media windows are supported by the strategy matrix below — the Bot API cannot turn a text message into a media one (or back), so a kind change recreates the message:
| was \ becomes | text | media |
|---|---|---|
| — (no message) | sendMessage | sendPhoto/sendVideo/… |
| text | editMessageText | delete (best effort) + send |
| media (any kind) | delete (best effort) + send | editMessageMedia |
deleteMessage is best effort (messages older than 48 hours cannot be
deleted): its failure is swallowed and the fresh message is sent anyway.
Also hosts the alert/toast helpers and the Bot API error classifiers
(is_not_modified & co) — the latter are useful outside dialogs too.
Types
The kind of the live dialog message. The Bot API cannot edit a text
message into a media one or back, so the engine tracks the kind to pick
the right strategy from the matrix in the module doc. All media messages
share one kind: editMessageMedia changes the file, the media type, and
the caption in a single call.
pub type MessageKind {
TextMessage
MediaMessage
}
Constructors
-
TextMessage -
MediaMessage
Why a window could not be rendered.
pub type RenderError {
ApiError(error.TelegaError)
InvalidButton(action_id: String, reason: String)
}
Constructors
-
ApiError(error.TelegaError)The Telegram API call failed (after the edit-fallback matrix).
-
InvalidButton(action_id: String, reason: String)A button is misconfigured: callback data over 64 bytes or a reserved
:in an action id. This is a developer error and must be visible, not silently degraded.
Values
pub fn alert(
ctx ctx: bot.Context(session, error, dependencies),
text text: String,
) -> Result(Nil, error.TelegaError)
Show a modal alert to the user who pressed the button. Call from
on_action before returning; the engine then skips its automatic
answer_callback_query for this event.
pub fn build_markup(
dialog_id dialog_id: String,
window_id window_id: String,
buttons buttons: List(List(types.DialogButton)),
) -> Result(
option.Option(types.InlineKeyboardMarkup),
RenderError,
)
Build the inline keyboard for a window, generating callback data by the
dlg:<dialog>:<window>:<action>[:<arg>] scheme and validating the 64-byte
limit and reserved characters per button.
pub fn callback_data(
dialog_id dialog_id: String,
window_id window_id: String,
action_id action_id: String,
arg arg: option.Option(String),
) -> String
The exact callback-data string for an action — the single place the
dlg: scheme is constructed. Build-time validation measures budgets
through this same function, so packing and validation can never diverge.
pub fn is_cant_be_edited(error error: error.TelegaError) -> Bool
The message exists but cannot be edited (e.g. not sent by the bot).
pub fn is_message_not_found(
error error: error.TelegaError,
) -> Bool
The message to edit no longer exists (deleted by the user or too old).
pub fn is_not_modified(error error: error.TelegaError) -> Bool
The edit was a no-op: new content equals the current one. Safe to treat as success.
pub const max_callback_data_bytes: Int
Telegram’s callback-data byte limit; validation and packing share it.
pub fn pack_callback_data(
dialog_id dialog_id: String,
window_id window_id: String,
action_id action_id: String,
arg arg: option.Option(String),
) -> Result(String, RenderError)
Build callback data for an action, checking the reserved : in the
action id and Telegram’s 64-byte limit. The w: action-id prefix is the
widget namespace (w:<widget_id>:<cmd>) and is the only place : is
allowed — the engine routes such presses to the widget’s on_event. The
bare id "w" is rejected too: with a :-carrying arg it would be
indistinguishable from a widget event on parse.
pub fn remove_keyboard(
ctx ctx: bot.Context(session, error, dependencies),
chat_id chat_id: Int,
message_id message_id: Int,
) -> Result(Nil, error.TelegaError)
Remove the inline keyboard from the live dialog message (used on Done).
Best effort: failures are reported but callers usually ignore them.
pub fn render_window(
ctx ctx: bot.Context(session, error, dependencies),
chat_id chat_id: Int,
message message: option.Option(#(Int, MessageKind)),
dialog_id dialog_id: String,
window_id window_id: String,
window window: types.RenderedWindow,
) -> Result(#(Int, MessageKind), RenderError)
Render a window into the live dialog message following the edit-or-send strategy matrix (see the module doc): send when there is no message yet, edit when the kind is unchanged, delete-and-resend when it changed. Edits fall back to a fresh send when the old message is gone. Returns the id and kind of the live message.
pub fn toast(
ctx ctx: bot.Context(session, error, dependencies),
text text: String,
) -> Result(Nil, error.TelegaError)
Show a toast notification at the top of the chat. Same contract as
alert, but without the modal dialog.