Better keyboard definition way with less code.

This commit is contained in:
Andrey Parhomenko 2023-09-19 14:38:57 +03:00
parent 86cfffc56f
commit 5a590a3cd0
2 changed files with 79 additions and 99 deletions

View file

@ -51,7 +51,7 @@ var (
startScreenButton = tg.NewButton("🏠 To the start screen"). startScreenButton = tg.NewButton("🏠 To the start screen").
ScreenChange("start") ScreenChange("start")
incDecKeyboard = tg.NewReply().Row( incDecKeyboard = tg.NewKeyboard().Row(
tg.NewButton("+").ActionFunc(func(c *tg.Context) { tg.NewButton("+").ActionFunc(func(c *tg.Context) {
d := ExtractSessionData(c) d := ExtractSessionData(c)
d.Counter++ d.Counter++
@ -66,9 +66,7 @@ var (
startScreenButton, startScreenButton,
) )
navKeyboard = tg.NewReply(). navKeyboard = tg.NewKeyboard().Row(
WithOneTime(true).
Row(
tg.NewButton("Inc/Dec").ScreenChange("start/inc-dec"), tg.NewButton("Inc/Dec").ScreenChange("start/inc-dec"),
).Row( ).Row(
tg.NewButton("Upper case").ActionFunc(func(c *tg.Context){ tg.NewButton("Upper case").ActionFunc(func(c *tg.Context){
@ -77,17 +75,14 @@ var (
tg.NewButton("Lower case").ScreenChange("start/lower-case"), tg.NewButton("Lower case").ScreenChange("start/lower-case"),
).Row( ).Row(
tg.NewButton("Send location").ScreenChange("start/send-location"), tg.NewButton("Send location").ScreenChange("start/send-location"),
) ).Reply().WithOneTime(true)
sendLocationKeyboard = tg.NewReply(). sendLocationKeyboard = tg.NewKeyboard().Row(
Row(
tg.NewButton("Send location"). tg.NewButton("Send location").
WithSendLocation(true). WithSendLocation(true).
ActionFunc(func(c *tg.Context) { ActionFunc(func(c *tg.Context) {
var err error
if c.Message.Location != nil {
l := c.Message.Location l := c.Message.Location
_, err = c.Sendf( c.Sendf(
"Longitude: %f\n"+ "Longitude: %f\n"+
"Latitude: %f\n"+ "Latitude: %f\n"+
"Heading: %d"+ "Heading: %d"+
@ -96,21 +91,15 @@ var (
l.Latitude, l.Latitude,
l.Heading, l.Heading,
) )
} else {
_, err = c.Sendf("Somehow location was not sent")
}
if err != nil {
c.Sendf("%q", err)
}
}), }),
).Row( ).Row(
startScreenButton, startScreenButton,
) ).Reply()
// The keyboard to return to the start screen. // The keyboard to return to the start screen.
navToStartKeyboard = tg.NewReply().Row( navToStartKeyboard = tg.NewKeyboard().Row(
startScreenButton, startScreenButton,
) ).Reply()
) )
var beh = tg.NewBehaviour(). var beh = tg.NewBehaviour().
@ -121,12 +110,12 @@ var beh = tg.NewBehaviour().
tg.NewScreen("start", tg.NewPage( tg.NewScreen("start", tg.NewPage(
"", "",
).WithInline( ).WithInline(
tg.NewInline().Row( tg.NewKeyboard().Row(
tg.NewButton("GoT Github page"). tg.NewButton("GoT Github page").
WithUrl("https://github.com/mojosa-software/got"), WithUrl("https://github.com/mojosa-software/got"),
).Widget(""), ).Inline().Widget("The bot started!"),
).WithReply( ).WithReply(
navKeyboard.Widget("The bot started!"), navKeyboard.Widget("Choose what you are interested in"),
), ),
), ),
tg.NewScreen("start/inc-dec", tg.NewPage( tg.NewScreen("start/inc-dec", tg.NewPage(
@ -135,7 +124,7 @@ var beh = tg.NewBehaviour().
"by saving the counter for each of users "+ "by saving the counter for each of users "+
"separately. ", "separately. ",
).WithReply( ).WithReply(
incDecKeyboard.Widget("Press the buttons to increment and decrement"), incDecKeyboard.Reply().Widget("Press the buttons to increment and decrement"),
).ActionFunc(func(c *tg.Context) { ).ActionFunc(func(c *tg.Context) {
// The function will be calleb before serving page. // The function will be calleb before serving page.
d := ExtractSessionData(c) d := ExtractSessionData(c)
@ -166,7 +155,7 @@ var beh = tg.NewBehaviour().
).WithReply( ).WithReply(
sendLocationKeyboard.Widget(""), sendLocationKeyboard.Widget(""),
).WithInline( ).WithInline(
tg.NewInline().Row( tg.NewKeyboard().Row(
tg.NewButton( tg.NewButton(
"Check", "Check",
).WithData( ).WithData(
@ -175,7 +164,7 @@ var beh = tg.NewBehaviour().
d := ExtractSessionData(c) d := ExtractSessionData(c)
c.Sendf("Counter = %d", d.Counter) c.Sendf("Counter = %d", d.Counter)
}), }),
).Widget("Press the button to display your counter"), ).Inline().Widget("Press the button to display your counter"),
), ),
), ),
).WithCommands( ).WithCommands(

View file

@ -8,39 +8,29 @@ import (
type Keyboard struct { type Keyboard struct {
// The action is called if there is no // The action is called if there is no
// defined action for the button. // defined action for the button.
Action *action Action Action
Rows []ButtonRow Rows []ButtonRow
buttonMap ButtonMap buttonMap ButtonMap
} }
// The type represents reply keyboards. // The type represents reply keyboards.
type ReplyKeyboard struct { type ReplyKeyboard struct {
Keyboard *Keyboard
// If true will be removed after one press. // If true will be removed after one press.
OneTime bool OneTime bool
// If true will remove the keyboard on send. // If true will remove the keyboard on send.
Remove bool Remove bool
} }
// The type represents keyboard to be emdedded into the messages. // Returns the new keyboard with specified rows.
type InlineKeyboard struct { func NewKeyboard(rows ...ButtonRow) *Keyboard {
Keyboard ret := &Keyboard{}
} ret.Rows = rows
// Returns new empty inline keyboard.
func NewInline() *InlineKeyboard {
ret := &InlineKeyboard{}
return ret
}
// Returns new empty reply keyboard.
func NewReply() *ReplyKeyboard {
ret := &ReplyKeyboard {}
return ret return ret
} }
// Adds a new button row to the current keyboard. // Adds a new button row to the current keyboard.
func (kbd *InlineKeyboard) Row(btns ...*Button) *InlineKeyboard { func (kbd *Keyboard) Row(btns ...*Button) *Keyboard {
// For empty row. We do not need that. // For empty row. We do not need that.
if len(btns) < 1 { if len(btns) < 1 {
return kbd return kbd
@ -49,17 +39,53 @@ func (kbd *InlineKeyboard) Row(btns ...*Button) *InlineKeyboard {
return kbd return kbd
} }
// Set default action for the buttons in keyboard. // Set the default action when no button provides
func (kbd *InlineKeyboard) WithAction(a Action) *InlineKeyboard { // key to the data we got.
kbd.Action = newAction(a) func (kbd *Keyboard) WithAction(a Action) *Keyboard {
kbd.Action = a
return kbd return kbd
} }
// Alias to WithAction to simpler define actions. // Alias to WithAction but better typing when setting
func (kbd *InlineKeyboard) ActionFunc(fn ActionFunc) *InlineKeyboard { // a specific function
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.
func (kbd Keyboard) ButtonMap() ButtonMap {
if kbd.buttonMap != nil {
return kbd.buttonMap
}
ret := make(ButtonMap)
for _, vi := range kbd.Rows {
for _, vj := range vi {
ret[vj.Key()] = vj
}
}
kbd.buttonMap = ret
return ret
}
// Convert the keyboard to the more specific inline one.
func (kbd *Keyboard) Inline() *InlineKeyboard {
ret := &InlineKeyboard{}
ret.Keyboard = kbd
return ret
}
func (kbd *Keyboard) Reply() *ReplyKeyboard {
ret := &ReplyKeyboard{}
ret.Keyboard = kbd
return ret
}
// The type represents keyboard to be emdedded into the messages.
type InlineKeyboard struct {
*Keyboard
}
// Transform the keyboard to widget with the specified text. // Transform the keyboard to widget with the specified text.
func (kbd *InlineKeyboard) Widget(text string) *InlineKeyboardWidget { func (kbd *InlineKeyboard) Widget(text string) *InlineKeyboardWidget {
ret := &InlineKeyboardWidget{} ret := &InlineKeyboardWidget{}
@ -68,27 +94,7 @@ func (kbd *InlineKeyboard) Widget(text string) *InlineKeyboardWidget {
return ret return ret
} }
// Adds a new button row to the current keyboard. // Transform the keyboard to widget with the specified text.
func (kbd *ReplyKeyboard) Row(btns ...*Button) *ReplyKeyboard {
// For empty row. We do not need that.
if len(btns) < 1 {
return kbd
}
kbd.Rows = append(kbd.Rows, btns)
return kbd
}
// Set default action for the keyboard.
func (kbd *ReplyKeyboard) WithAction(a Action) *ReplyKeyboard {
kbd.Action = newAction(a)
return kbd
}
// Alias to WithAction for simpler callback declarations.
func (kbd *ReplyKeyboard) ActionFunc(fn ActionFunc) *ReplyKeyboard {
return kbd.WithAction(fn)
}
func (kbd *ReplyKeyboard) Widget(text string) *ReplyKeyboardWidget { func (kbd *ReplyKeyboard) Widget(text string) *ReplyKeyboardWidget {
ret := &ReplyKeyboardWidget{} ret := &ReplyKeyboardWidget{}
ret.ReplyKeyboard = kbd ret.ReplyKeyboard = kbd
@ -147,19 +153,4 @@ func (kbd *ReplyKeyboard) WithOneTime(oneTime bool) *ReplyKeyboard {
return kbd return kbd
} }
// Returns the map of buttons. Used to define the Action.
func (kbd Keyboard) ButtonMap() ButtonMap {
if kbd.buttonMap != nil {
return kbd.buttonMap
}
ret := make(ButtonMap)
for _, vi := range kbd.Rows {
for _, vj := range vi {
ret[vj.Key()] = vj
}
}
kbd.buttonMap = ret
return ret
}