From cc8f7e82e2412e5e577d0efbc7b229e89781b808 Mon Sep 17 00:00:00 2001 From: surdeus Date: Tue, 19 Dec 2023 22:35:57 +0300 Subject: [PATCH] feat: implemented the dynamic inline keyboards via the panel component. --- cmd/test/main.go | 49 ++++++++++++++++++++++++ context.go | 8 ++++ inline.go | 96 ++++++++++++++++++++++++++---------------------- keyboard.go | 10 ++++- panel.go | 40 ++++++++++++++++++++ 5 files changed, 158 insertions(+), 45 deletions(-) create mode 100644 panel.go diff --git a/cmd/test/main.go b/cmd/test/main.go index 190067c..832b45f 100644 --- a/cmd/test/main.go +++ b/cmd/test/main.go @@ -111,6 +111,8 @@ var beh = tg.NewBehaviour(). tg.NewButton("Mutate messages").Go("/mutate-messages"), ).Row( tg.NewButton("Send location").Go("/send-location"), + ).Row( + tg.NewButton("Dynamic panel").Go("panel"), ).Reply(), ), @@ -124,6 +126,53 @@ var beh = tg.NewBehaviour(). } }), + tg.NewNode( + "panel", + tg.RenderFunc(func(c *tg.Context) tg.UI { + var ( + n = 0 + ln = 4 + panel *tg.PanelCompo + ) + + panel = tg.NewMessage( + "Some panel", + ).Panel(c, tg.RowserFunc(func(c *tg.Context) []tg.ButtonRow{ + btns := []tg.ButtonRow{ + tg.ButtonRow{tg.NewButton("Static shit")}, + } + for i:=0 ; i 0 { + sendConfig.Message.ReplyMarkup = compo.Inline.ToApi() + } return sendConfig } +// Update the component on the client side. func (compo *InlineCompo) Update(c *Context) { - var edit tgbotapi.Chattable - markup := compo.Inline.ToApi() - ln := len(markup.InlineKeyboard) - if ln == 0 || compo.Inline.Rows == nil { - edit = tgbotapi.NewEditMessageText( - c.Session.Id.ToApi(), - compo.Message.MessageID, - compo.Text, - ) - } else { - edit = tgbotapi.NewEditMessageTextAndMarkup( - c.Session.Id.ToApi(), - compo.Message.MessageID, - compo.Text, - markup, - ) + 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.Session.Id.ToApi(), + compo.Message.MessageID, + compo.Text, + ) + } else { + edit = tgbotapi.NewEditMessageTextAndMarkup( + c.Session.Id.ToApi(), + compo.Message.MessageID, + compo.Text, + markup, + ) + } + msg, _ := c.Bot.Api.Send(edit) + compo.Message = &msg } - msg, _ := c.Bot.Api.Send(edit) - compo.Message = &msg + compo.buttonMap = compo.MakeButtonMap() } // Implementing the Filterer interface. @@ -82,33 +88,35 @@ func (compo *InlineCompo) Filter(u *Update) bool { } // Implementing the Server interface. -func (widget *InlineCompo) Serve(c *Context) { - btns := widget.ButtonMap() +func (compo *InlineCompo) Serve(c *Context) { for u := range c.Input() { - var act Action - cb := tgbotapi.NewCallback( - u.CallbackQuery.ID, - u.CallbackQuery.Data, - ) - data := u.CallbackQuery.Data - - _, err := c.Bot.Api.Request(cb) - if err != nil { - //return err - continue - } - - btn, ok := btns[data] - if !ok { - continue - } - if btn != nil { - act = btn.Action - } else if widget.Action != nil { - act = widget.Action - } - c.WithUpdate(u).Run(act) + compo.OnOneUpdate(c, u) } } +func (compo *InlineCompo) OnOneUpdate(c *Context, u *Update) { + 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 + } + + btn, ok := btns[data] + if !ok { + return + } + if btn != nil { + act = btn.Action + } else if compo.Action != nil { + act = compo.Action + } + c.WithUpdate(u).Run(act) +} diff --git a/keyboard.go b/keyboard.go index e4d4801..ac9c839 100644 --- a/keyboard.go +++ b/keyboard.go @@ -79,8 +79,16 @@ func (kbd *Keyboard) ActionFunc(fn ActionFunc) *Keyboard { return kbd.WithAction(fn) } -// Returns the map of buttons. Used to define the Action. +// Returns the map of buttons. func (kbd Keyboard) ButtonMap() ButtonMap { + if kbd.buttonMap == nil { + kbd.buttonMap = kbd.MakeButtonMap() + } + return kbd.buttonMap +} + +// Returns the map of buttons on the most fresh version of the keyboard. +func (kbd Keyboard) MakeButtonMap() ButtonMap { ret := make(ButtonMap) for _, vi := range kbd.Rows { for _, vj := range vi { diff --git a/panel.go b/panel.go new file mode 100644 index 0000000..e2e4b55 --- /dev/null +++ b/panel.go @@ -0,0 +1,40 @@ +package tg + +type Rowser interface { + MakeRows(c *Context) []ButtonRow +} + +type RowserFunc func(c *Context) []ButtonRow +func (fn RowserFunc) MakeRows(c *Context) []ButtonRow { + return fn(c) +} + +// The type represents the inline panel with +// scrollable via buttons content. +// Can be used for example to show users via SQL and offset +// or something like that. +type PanelCompo struct { + *InlineCompo + Rowser Rowser +} + +// Transform to the panel with dynamic rows. +func (compo *MessageCompo) Panel( + c *Context, // The context that all the buttons will get. + rowser Rowser, // The rows generator. +) *PanelCompo { + ret := &PanelCompo{} + ret.InlineCompo = compo.Inline( + NewKeyboard( + rowser.MakeRows(c)..., + ).Inline(), + ) + ret.Rowser = rowser + return ret +} + +func (compo *PanelCompo) Update(c *Context) { + compo.Rows = compo.Rowser.MakeRows(c) + compo.InlineCompo.Update(c) +} +