From 5a590a3cd0549432a6d36382d873ff2dbe7da91f Mon Sep 17 00:00:00 2001 From: surdeus Date: Tue, 19 Sep 2023 14:38:57 +0300 Subject: [PATCH] Better keyboard definition way with less code. --- cmd/test/main.go | 71 +++++++++++++------------------ tg/keyboard.go | 107 ++++++++++++++++++++++------------------------- 2 files changed, 79 insertions(+), 99 deletions(-) diff --git a/cmd/test/main.go b/cmd/test/main.go index d4fb134..bb3283e 100644 --- a/cmd/test/main.go +++ b/cmd/test/main.go @@ -51,7 +51,7 @@ var ( startScreenButton = tg.NewButton("🏠 To the start screen"). ScreenChange("start") - incDecKeyboard = tg.NewReply().Row( + incDecKeyboard = tg.NewKeyboard().Row( tg.NewButton("+").ActionFunc(func(c *tg.Context) { d := ExtractSessionData(c) d.Counter++ @@ -66,51 +66,40 @@ var ( startScreenButton, ) - navKeyboard = tg.NewReply(). - WithOneTime(true). - Row( - tg.NewButton("Inc/Dec").ScreenChange("start/inc-dec"), - ).Row( + navKeyboard = tg.NewKeyboard().Row( + tg.NewButton("Inc/Dec").ScreenChange("start/inc-dec"), + ).Row( tg.NewButton("Upper case").ActionFunc(func(c *tg.Context){ c.ChangeScreen("start/upper-case", "this shit", "works") }), tg.NewButton("Lower case").ScreenChange("start/lower-case"), ).Row( tg.NewButton("Send location").ScreenChange("start/send-location"), - ) + ).Reply().WithOneTime(true) - sendLocationKeyboard = tg.NewReply(). - Row( - tg.NewButton("Send location"). - WithSendLocation(true). - ActionFunc(func(c *tg.Context) { - var err error - if c.Message.Location != nil { - l := c.Message.Location - _, err = c.Sendf( - "Longitude: %f\n"+ - "Latitude: %f\n"+ - "Heading: %d"+ - "", - l.Longitude, - l.Latitude, - l.Heading, - ) - } else { - _, err = c.Sendf("Somehow location was not sent") - } - if err != nil { - c.Sendf("%q", err) - } - }), - ).Row( + sendLocationKeyboard = tg.NewKeyboard().Row( + tg.NewButton("Send location"). + WithSendLocation(true). + ActionFunc(func(c *tg.Context) { + l := c.Message.Location + c.Sendf( + "Longitude: %f\n"+ + "Latitude: %f\n"+ + "Heading: %d"+ + "", + l.Longitude, + l.Latitude, + l.Heading, + ) + }), + ).Row( startScreenButton, - ) + ).Reply() // The keyboard to return to the start screen. - navToStartKeyboard = tg.NewReply().Row( + navToStartKeyboard = tg.NewKeyboard().Row( startScreenButton, - ) + ).Reply() ) var beh = tg.NewBehaviour(). @@ -121,12 +110,12 @@ var beh = tg.NewBehaviour(). tg.NewScreen("start", tg.NewPage( "", ).WithInline( - tg.NewInline().Row( + tg.NewKeyboard().Row( tg.NewButton("GoT Github page"). WithUrl("https://github.com/mojosa-software/got"), - ).Widget(""), + ).Inline().Widget("The bot started!"), ).WithReply( - navKeyboard.Widget("The bot started!"), + navKeyboard.Widget("Choose what you are interested in"), ), ), tg.NewScreen("start/inc-dec", tg.NewPage( @@ -135,7 +124,7 @@ var beh = tg.NewBehaviour(). "by saving the counter for each of users "+ "separately. ", ).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) { // The function will be calleb before serving page. d := ExtractSessionData(c) @@ -166,7 +155,7 @@ var beh = tg.NewBehaviour(). ).WithReply( sendLocationKeyboard.Widget(""), ).WithInline( - tg.NewInline().Row( + tg.NewKeyboard().Row( tg.NewButton( "Check", ).WithData( @@ -175,7 +164,7 @@ var beh = tg.NewBehaviour(). d := ExtractSessionData(c) c.Sendf("Counter = %d", d.Counter) }), - ).Widget("Press the button to display your counter"), + ).Inline().Widget("Press the button to display your counter"), ), ), ).WithCommands( diff --git a/tg/keyboard.go b/tg/keyboard.go index 0bd579d..fcc9d9a 100644 --- a/tg/keyboard.go +++ b/tg/keyboard.go @@ -8,39 +8,29 @@ import ( type Keyboard struct { // The action is called if there is no // defined action for the button. - Action *action + Action Action Rows []ButtonRow buttonMap ButtonMap } // The type represents reply keyboards. type ReplyKeyboard struct { - Keyboard + *Keyboard // If true will be removed after one press. OneTime bool // If true will remove the keyboard on send. Remove bool } -// The type represents keyboard to be emdedded into the messages. -type InlineKeyboard struct { - Keyboard -} - -// Returns new empty inline keyboard. -func NewInline() *InlineKeyboard { - ret := &InlineKeyboard{} - return ret -} - -// Returns new empty reply keyboard. -func NewReply() *ReplyKeyboard { - ret := &ReplyKeyboard {} +// Returns the new keyboard with specified rows. +func NewKeyboard(rows ...ButtonRow) *Keyboard { + ret := &Keyboard{} + ret.Rows = rows return ret } // 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. if len(btns) < 1 { return kbd @@ -49,17 +39,53 @@ func (kbd *InlineKeyboard) Row(btns ...*Button) *InlineKeyboard { return kbd } -// Set default action for the buttons in keyboard. -func (kbd *InlineKeyboard) WithAction(a Action) *InlineKeyboard { - kbd.Action = newAction(a) +// Set the default action when no button provides +// key to the data we got. +func (kbd *Keyboard) WithAction(a Action) *Keyboard { + kbd.Action = a return kbd } -// Alias to WithAction to simpler define actions. -func (kbd *InlineKeyboard) ActionFunc(fn ActionFunc) *InlineKeyboard { +// Alias to WithAction but better typing when setting +// a specific function +func (kbd *Keyboard) ActionFunc(fn ActionFunc) *Keyboard { 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. func (kbd *InlineKeyboard) Widget(text string) *InlineKeyboardWidget { ret := &InlineKeyboardWidget{} @@ -68,27 +94,7 @@ func (kbd *InlineKeyboard) Widget(text string) *InlineKeyboardWidget { return ret } -// Adds a new button row to the current keyboard. -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) -} - +// Transform the keyboard to widget with the specified text. func (kbd *ReplyKeyboard) Widget(text string) *ReplyKeyboardWidget { ret := &ReplyKeyboardWidget{} ret.ReplyKeyboard = kbd @@ -147,19 +153,4 @@ func (kbd *ReplyKeyboard) WithOneTime(oneTime bool) *ReplyKeyboard { 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 -}