feat: implemented the dynamic inline keyboards via the panel component.
This commit is contained in:
parent
fbe0cf1c44
commit
cc8f7e82e2
5 changed files with 158 additions and 45 deletions
|
@ -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<ln ; i++ {
|
||||
num := 1 + n * ln + i
|
||||
btns = append(btns, tg.ButtonRow{
|
||||
tg.NewButton("%d", num).WithAction(tg.Func(func(c *tg.Context){
|
||||
c.Sendf("%d", num*num)
|
||||
})),
|
||||
tg.NewButton("%d", num*num),
|
||||
})
|
||||
}
|
||||
btns = append(btns, tg.ButtonRow{
|
||||
tg.NewButton("Prev").WithAction(tg.ActionFunc(func(c *tg.Context){
|
||||
n--
|
||||
panel.Update(c)
|
||||
})),
|
||||
tg.NewButton("Next").WithAction(tg.ActionFunc(func(c *tg.Context){
|
||||
n++
|
||||
panel.Update(c)
|
||||
})),
|
||||
})
|
||||
|
||||
return btns
|
||||
}))
|
||||
|
||||
return tg.UI{
|
||||
panel,
|
||||
tg.NewMessage("").Reply(
|
||||
backKeyboard.Reply(),
|
||||
),
|
||||
}
|
||||
}),
|
||||
),
|
||||
|
||||
tg.NewNode(
|
||||
"mutate-messages", tg.RenderFunc(func(c *tg.Context) tg.UI {
|
||||
return tg.UI{
|
||||
|
|
|
@ -46,6 +46,10 @@ type context struct {
|
|||
//path, prevPath Path
|
||||
}
|
||||
|
||||
type Contexter interface {
|
||||
GetContext() *Context
|
||||
}
|
||||
|
||||
// Interface to interact with the user.
|
||||
type Context struct {
|
||||
*context
|
||||
|
@ -59,6 +63,10 @@ type Context struct {
|
|||
input *UpdateChan
|
||||
}
|
||||
|
||||
func (c *Context) GetContext() *Context {
|
||||
return c
|
||||
}
|
||||
|
||||
// General type function to define actions, single component widgets
|
||||
// and components themselves.
|
||||
type Func func(*Context)
|
||||
|
|
96
inline.go
96
inline.go
|
@ -40,31 +40,37 @@ func (compo *InlineCompo) SendConfig(
|
|||
sid SessionId, bot *Bot,
|
||||
) (*SendConfig) {
|
||||
sendConfig := compo.MessageCompo.SendConfig(sid, bot)
|
||||
sendConfig.Message.ReplyMarkup = compo.Inline.ToApi()
|
||||
if len(compo.Inline.Rows) > 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)
|
||||
}
|
||||
|
||||
|
|
10
keyboard.go
10
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 {
|
||||
|
|
40
panel.go
Normal file
40
panel.go
Normal file
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in a new issue