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"),
|
tg.NewButton("Mutate messages").Go("/mutate-messages"),
|
||||||
).Row(
|
).Row(
|
||||||
tg.NewButton("Send location").Go("/send-location"),
|
tg.NewButton("Send location").Go("/send-location"),
|
||||||
|
).Row(
|
||||||
|
tg.NewButton("Dynamic panel").Go("panel"),
|
||||||
).Reply(),
|
).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(
|
tg.NewNode(
|
||||||
"mutate-messages", tg.RenderFunc(func(c *tg.Context) tg.UI {
|
"mutate-messages", tg.RenderFunc(func(c *tg.Context) tg.UI {
|
||||||
return tg.UI{
|
return tg.UI{
|
||||||
|
|
|
@ -46,6 +46,10 @@ type context struct {
|
||||||
//path, prevPath Path
|
//path, prevPath Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Contexter interface {
|
||||||
|
GetContext() *Context
|
||||||
|
}
|
||||||
|
|
||||||
// Interface to interact with the user.
|
// Interface to interact with the user.
|
||||||
type Context struct {
|
type Context struct {
|
||||||
*context
|
*context
|
||||||
|
@ -59,6 +63,10 @@ type Context struct {
|
||||||
input *UpdateChan
|
input *UpdateChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Context) GetContext() *Context {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// General type function to define actions, single component widgets
|
// General type function to define actions, single component widgets
|
||||||
// and components themselves.
|
// and components themselves.
|
||||||
type Func func(*Context)
|
type Func func(*Context)
|
||||||
|
|
96
inline.go
96
inline.go
|
@ -40,31 +40,37 @@ func (compo *InlineCompo) SendConfig(
|
||||||
sid SessionId, bot *Bot,
|
sid SessionId, bot *Bot,
|
||||||
) (*SendConfig) {
|
) (*SendConfig) {
|
||||||
sendConfig := compo.MessageCompo.SendConfig(sid, bot)
|
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
|
return sendConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the component on the client side.
|
||||||
func (compo *InlineCompo) Update(c *Context) {
|
func (compo *InlineCompo) Update(c *Context) {
|
||||||
var edit tgbotapi.Chattable
|
if compo.Message != nil {
|
||||||
markup := compo.Inline.ToApi()
|
var edit tgbotapi.Chattable
|
||||||
ln := len(markup.InlineKeyboard)
|
markup := compo.Inline.ToApi()
|
||||||
if ln == 0 || compo.Inline.Rows == nil {
|
ln := len(markup.InlineKeyboard)
|
||||||
edit = tgbotapi.NewEditMessageText(
|
if ln == 0 || compo.Inline.Rows == nil {
|
||||||
c.Session.Id.ToApi(),
|
edit = tgbotapi.NewEditMessageText(
|
||||||
compo.Message.MessageID,
|
c.Session.Id.ToApi(),
|
||||||
compo.Text,
|
compo.Message.MessageID,
|
||||||
)
|
compo.Text,
|
||||||
} else {
|
)
|
||||||
edit = tgbotapi.NewEditMessageTextAndMarkup(
|
} else {
|
||||||
c.Session.Id.ToApi(),
|
edit = tgbotapi.NewEditMessageTextAndMarkup(
|
||||||
compo.Message.MessageID,
|
c.Session.Id.ToApi(),
|
||||||
compo.Text,
|
compo.Message.MessageID,
|
||||||
markup,
|
compo.Text,
|
||||||
)
|
markup,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
msg, _ := c.Bot.Api.Send(edit)
|
||||||
|
compo.Message = &msg
|
||||||
}
|
}
|
||||||
msg, _ := c.Bot.Api.Send(edit)
|
compo.buttonMap = compo.MakeButtonMap()
|
||||||
compo.Message = &msg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementing the Filterer interface.
|
// Implementing the Filterer interface.
|
||||||
|
@ -82,33 +88,35 @@ func (compo *InlineCompo) Filter(u *Update) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementing the Server interface.
|
// Implementing the Server interface.
|
||||||
func (widget *InlineCompo) Serve(c *Context) {
|
func (compo *InlineCompo) Serve(c *Context) {
|
||||||
btns := widget.ButtonMap()
|
|
||||||
for u := range c.Input() {
|
for u := range c.Input() {
|
||||||
var act Action
|
compo.OnOneUpdate(c, u)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
return kbd.WithAction(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the map of buttons. Used to define the Action.
|
// Returns the map of buttons.
|
||||||
func (kbd Keyboard) ButtonMap() ButtonMap {
|
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)
|
ret := make(ButtonMap)
|
||||||
for _, vi := range kbd.Rows {
|
for _, vi := range kbd.Rows {
|
||||||
for _, vj := range vi {
|
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