From ce13b1967658012da013965d60f44f0cd4a6ccf5 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Wed, 21 Jan 2026 15:53:30 +0300 Subject: [PATCH] inline keyboard --- bot.go | 43 +++++++++++++++++++++++++++++++------------ keyboard.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ methods.go | 2 +- types.go | 8 +++++++- 4 files changed, 88 insertions(+), 14 deletions(-) diff --git a/bot.go b/bot.go index 690f10c..a6c64ba 100644 --- a/bot.go +++ b/bot.go @@ -291,13 +291,20 @@ func (b *Bot) handleMessage(update *Update, ctx *MsgContext) { } func (b *Bot) handleCallback(update *Update, ctx *MsgContext) { + data := new(CallbackData) + err := json.Unmarshal([]byte(update.CallbackQuery.Data), data) + if err != nil { + b.logger.Error(err) + return + } + for _, plugin := range b.plugins { - for payload := range plugin.Payloads { - if !strings.HasPrefix(update.CallbackQuery.Data, payload) { - continue - } - go plugin.ExecutePayload(payload, ctx, b.dbContext) + _, ok := plugin.Payloads[data.Command] + if !ok { + continue } + go plugin.ExecutePayload(data.Command, ctx, b.dbContext) + break } } @@ -312,27 +319,39 @@ func (b *Bot) checkPrefixes(text string) (string, bool) { type AnswerMessage struct { MessageID int + Text string IsMedia bool + Keyboard *InlineKeyboard ctx *MsgContext } -func (ctx *MsgContext) Answer(text string) *AnswerMessage { - msg, err := ctx.Bot.SendMessage(&SendMessageP{ +func (ctx *MsgContext) answer(text string, keyboard *InlineKeyboard) *AnswerMessage { + params := &SendMessageP{ ChatID: ctx.Msg.Chat.ID, Text: text, ParseMode: ParseMD, - }) + } + if keyboard != nil { + params.ReplyMarkup = keyboard.Get() + } + + msg, err := ctx.Bot.SendMessage(params) if err != nil { ctx.Bot.logger.Error(err) return nil } return &AnswerMessage{ - MessageID: msg.MessageID, ctx: ctx, IsMedia: false, + MessageID: msg.MessageID, ctx: ctx, IsMedia: false, Text: text, } } +func (ctx *MsgContext) Answer(text string) *AnswerMessage { + return ctx.answer(text, nil) +} func (ctx *MsgContext) Answerf(template string, args ...any) *AnswerMessage { - test := fmt.Sprintf(template, args...) - return ctx.Answer(test) + return ctx.answer(fmt.Sprintf(template, args...), nil) +} +func (ctx *MsgContext) Keyboard(text string, kb *InlineKeyboard) *AnswerMessage { + return ctx.answer(text, kb) } func (ctx *MsgContext) AnswerPhoto(photoId string, text string) *AnswerMessage { @@ -346,7 +365,7 @@ func (ctx *MsgContext) AnswerPhoto(photoId string, text string) *AnswerMessage { ctx.Bot.logger.Error(err) } return &AnswerMessage{ - MessageID: ctx.Msg.MessageID, ctx: ctx, IsMedia: true, + MessageID: ctx.Msg.MessageID, ctx: ctx, IsMedia: true, Text: text, } } diff --git a/keyboard.go b/keyboard.go index edc15f0..14cba31 100644 --- a/keyboard.go +++ b/keyboard.go @@ -1,4 +1,53 @@ package laniakea +import "encoding/json" + type InlineKeyboard struct { + CurrentLine []InlineKeyboardButton + Lines [][]InlineKeyboardButton +} + +func NewInlineKeyboard() *InlineKeyboard { + return &InlineKeyboard{ + CurrentLine: make([]InlineKeyboardButton, 0), + Lines: make([][]InlineKeyboardButton, 0), + } +} + +func (in *InlineKeyboard) append(button InlineKeyboardButton) *InlineKeyboard { + in.CurrentLine = append(in.CurrentLine, button) + return in +} +func (in *InlineKeyboard) AddUrlButton(text, url string) *InlineKeyboard { + return in.append(InlineKeyboardButton{Text: text, URL: url}) +} +func (in *InlineKeyboard) AddCallbackButton(text string, data CallbackData) *InlineKeyboard { + return in.append(InlineKeyboardButton{Text: text, CallbackData: data.ToJson()}) +} + +func (in *InlineKeyboard) AddLine() *InlineKeyboard { + in.Lines = append(in.Lines, in.CurrentLine) + in.CurrentLine = make([]InlineKeyboardButton, 0) + return in +} +func (in *InlineKeyboard) Get() *InlineKeyboardMarkup { + if len(in.CurrentLine) > 0 { + in.Lines = append(in.Lines, in.CurrentLine) + } + return &InlineKeyboardMarkup{ + InlineKeyboard: in.Lines, + } +} + +type CallbackData struct { + Command string `json:"cmd"` + Args []any `json:"args"` +} + +func (d *CallbackData) ToJson() string { + data, err := json.Marshal(d) + if err != nil { + return `{"cmd":""}` + } + return string(data) } diff --git a/methods.go b/methods.go index 87375fd..6fd6040 100644 --- a/methods.go +++ b/methods.go @@ -62,7 +62,7 @@ type SendMessageP struct { AllowPaidBroadcast bool `json:"allow_paid_broadcast,omitempty"` MessageEffectID string `json:"message_effect_id,omitempty"` ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` - InlineKeyboardMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` // ReplyKeyboardMarkup *ReplyKeyboardMarkup `json:"reply_markup,omitempty"` } diff --git a/types.go b/types.go index 1a79e4b..549eeef 100644 --- a/types.go +++ b/types.go @@ -43,6 +43,10 @@ type Chat struct { IsForum bool `json:"is_forum,omitempty"` } +type MessageReplyMarkup struct { + InlineKeyboard *InlineKeyboardMarkup `json:"inline_keyboard"` +} + type Message struct { MessageID int `json:"message_id"` MessageThreadID int `json:"message_thread_id,omitempty"` @@ -53,6 +57,8 @@ type Message struct { Photo []*PhotoSize `json:"photo,omitempty"` Caption string `json:"caption,omitempty"` ReplyToMessage *Message `json:"reply_to_message"` + + ReplyMarkup *MessageReplyMarkup `json:"reply_markup,omitempty"` } type InaccessableMessage struct { @@ -103,7 +109,7 @@ type LinkPreviewOptions struct { } type InlineKeyboardMarkup struct { - InlineKeyboard [][]*InlineKeyboardButton `json:"inline_keyboard"` + InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"` } type InlineKeyboardButton struct {