tg/inline.go

135 lines
2.7 KiB
Go

package tg
import (
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
// The type represents keyboard to be emdedded
// into the messages (inline in Telegram terms).
type Inline struct {
Keyboard
}
// Convert the inline keyboard to markup for the tgbotapi.
func (kbd Inline) ToAPI() tgbotapi.InlineKeyboardMarkup {
rows := [][]tgbotapi.InlineKeyboardButton{}
for _, row := range kbd.Rows {
if row == nil {
continue
}
buttons := []tgbotapi.InlineKeyboardButton{}
for _, button := range row {
if !button.Valid {
continue
}
buttons = append(buttons, button.ToTelegramInline())
}
rows = append(rows, buttons)
}
return tgbotapi.NewInlineKeyboardMarkup(rows...)
}
// The type implements message with an inline keyboard.
type InlineCompo struct {
MessageCompo
Inline
}
// Implementing the Sendable interface.
func (compo *InlineCompo) SendConfig(
sid SessionID, bot *Bot,
) (SendConfig) {
sendConfig := compo.MessageCompo.SendConfig(sid, bot)
msg := sendConfig.Chattable.(tgbotapi.MessageConfig)
if len(compo.Inline.Rows) > 0 {
msg.ReplyMarkup = compo.Inline.ToAPI()
}
sendConfig.Chattable = msg
return sendConfig
}
// Update the component on the client side.
// Requires exactly the pointer but not the value
// cause it changes insides of the structure.
func (compo *InlineCompo) Update(c Context) error {
if compo.Message != nil {
var edit tgbotapi.Chattable
markup := compo.Inline.ToAPI()
ln := len(markup.InlineKeyboard)
if ln == 0 || compo.Inline.Rows == nil {
edit = tgbotapi.NewEditMessageText(
c.SessionID().ToAPI(),
compo.Message.MessageID,
compo.Text,
)
} else {
edit = tgbotapi.NewEditMessageTextAndMarkup(
c.SessionID().ToAPI(),
compo.Message.MessageID,
compo.Text,
markup,
)
}
msg, err := c.Bot().API().Send(edit)
if err != nil {
return err
}
compo.Message = &msg
}
return nil
}
// Implementing the Filterer interface.
func (compo *InlineCompo) Filter(u Update) bool {
if u.CallbackQuery == nil {
return true
}
if u.CallbackQuery.Message.MessageID !=
compo.Message.MessageID {
return true
}
return false
}
// Implementing the Server interface.
func (compo *InlineCompo) Serve(c Context) {
for u := range c.Input() {
compo.OnOneUpdate(c, u)
}
}
func (compo *InlineCompo) OnOneUpdate(c Context, u Update) error {
var act Action
btns := compo.ButtonMap()
cb := tgbotapi.NewCallback(
u.CallbackQuery.ID,
u.CallbackQuery.Data,
)
data := u.CallbackQuery.Data
_, err := c.Bot().API().Request(cb)
if err != nil {
return err
}
btn, ok := btns[data]
if !ok {
return nil
}
if btn.Action != nil {
act = btn.Action
} else if compo.Action != nil {
act = compo.Action
}
c.WithUpdate(u).Run(act)
return nil
}