Simplified the NewButton call and implemented location sending handling.
This commit is contained in:
parent
44185e92af
commit
bbe076f29a
5 changed files with 111 additions and 52 deletions
|
@ -12,27 +12,26 @@ type UserData struct {
|
||||||
Counter int
|
Counter int
|
||||||
}
|
}
|
||||||
|
|
||||||
var startScreenButton = tx.NewButton().
|
var startScreenButton = tx.NewButton("🏠 To the start screen").
|
||||||
WithText("🏠 To the start screen").
|
|
||||||
ScreenChange("start")
|
ScreenChange("start")
|
||||||
|
|
||||||
var beh = tx.NewBehaviour().
|
var beh = tx.NewBehaviour().
|
||||||
|
|
||||||
// The function will be called every time
|
// The function will be called every time
|
||||||
// the bot is started.
|
// the bot is started.
|
||||||
OnStartFunc(func(c *tx.Context) {
|
OnStartFunc(func(c *tx.A) {
|
||||||
c.V = &UserData{}
|
c.V = &UserData{}
|
||||||
c.ChangeScreen("start")
|
c.ChangeScreen("start")
|
||||||
}).WithKeyboards(
|
}).WithKeyboards(
|
||||||
|
|
||||||
// Increment/decrement keyboard.
|
// Increment/decrement keyboard.
|
||||||
tx.NewKeyboard("inc/dec").Row(
|
tx.NewKeyboard("inc/dec").Row(
|
||||||
tx.NewButton().WithText("+").ActionFunc(func(c *tx.Context) {
|
tx.NewButton("+").ActionFunc(func(c *tx.A) {
|
||||||
d := c.V.(*UserData)
|
d := c.V.(*UserData)
|
||||||
d.Counter++
|
d.Counter++
|
||||||
c.Sendf("%d", d.Counter)
|
c.Sendf("%d", d.Counter)
|
||||||
}),
|
}),
|
||||||
tx.NewButton().WithText("-").ActionFunc(func(c *tx.Context) {
|
tx.NewButton("-").ActionFunc(func(c *tx.A) {
|
||||||
d := c.V.(*UserData)
|
d := c.V.(*UserData)
|
||||||
d.Counter--
|
d.Counter--
|
||||||
c.Sendf("%d", d.Counter)
|
c.Sendf("%d", d.Counter)
|
||||||
|
@ -43,14 +42,37 @@ var beh = tx.NewBehaviour().
|
||||||
|
|
||||||
// The navigational keyboard.
|
// The navigational keyboard.
|
||||||
tx.NewKeyboard("nav").Row(
|
tx.NewKeyboard("nav").Row(
|
||||||
tx.NewButton().WithText("Inc/Dec").ScreenChange("inc/dec"),
|
tx.NewButton("Inc/Dec").ScreenChange("inc/dec"),
|
||||||
).Row(
|
).Row(
|
||||||
tx.NewButton().WithText("Upper case").ScreenChange("upper-case"),
|
tx.NewButton("Upper case").ScreenChange("upper-case"),
|
||||||
tx.NewButton().WithText("Lower case").ScreenChange("lower-case"),
|
tx.NewButton("Lower case").ScreenChange("lower-case"),
|
||||||
|
).Row(
|
||||||
|
tx.NewButton("Send location").
|
||||||
|
WithSendLocation(true).
|
||||||
|
ActionFunc(func(c *tx.A) {
|
||||||
|
var err error
|
||||||
|
if c.U.Message.Location != nil {
|
||||||
|
l := c.U.Message.Location
|
||||||
|
err = c.Sendf(
|
||||||
|
"Longitude: %f\n"+
|
||||||
|
"Latitude: %f\n"+
|
||||||
|
"Heading: %d"+
|
||||||
|
"",
|
||||||
|
l.Longitude,
|
||||||
|
l.Latitude,
|
||||||
|
l.Heading,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
err = c.Send("Somehow wrong location was sent")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
c.Send(err)
|
||||||
|
}
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
|
|
||||||
tx.NewKeyboard("istart").Row(
|
tx.NewKeyboard("istart").Row(
|
||||||
tx.NewButton().WithText("GoT Github page").
|
tx.NewButton("GoT Github page").
|
||||||
WithUrl("https://github.com/mojosa-software/got"),
|
WithUrl("https://github.com/mojosa-software/got"),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -78,7 +100,7 @@ var beh = tx.NewBehaviour().
|
||||||
).
|
).
|
||||||
Keyboard("inc/dec").
|
Keyboard("inc/dec").
|
||||||
// The function will be called when reaching the screen.
|
// The function will be called when reaching the screen.
|
||||||
ActionFunc(func(c *tx.Context) {
|
ActionFunc(func(c *tx.A) {
|
||||||
d := c.V.(*UserData)
|
d := c.V.(*UserData)
|
||||||
c.Sendf("Current counter value = %d", d.Counter)
|
c.Sendf("Current counter value = %d", d.Counter)
|
||||||
}),
|
}),
|
||||||
|
@ -95,12 +117,12 @@ var beh = tx.NewBehaviour().
|
||||||
).WithCommands(
|
).WithCommands(
|
||||||
tx.NewCommand("hello").
|
tx.NewCommand("hello").
|
||||||
Desc("sends the 'Hello, World!' message back").
|
Desc("sends the 'Hello, World!' message back").
|
||||||
ActionFunc(func(c *tx.Context) {
|
ActionFunc(func(c *tx.A) {
|
||||||
c.Send("Hello, World!")
|
c.Send("Hello, World!")
|
||||||
}),
|
}),
|
||||||
tx.NewCommand("read").
|
tx.NewCommand("read").
|
||||||
Desc("reads a string and sends it back").
|
Desc("reads a string and sends it back").
|
||||||
ActionFunc(func(c *tx.Context) {
|
ActionFunc(func(c *tx.A) {
|
||||||
c.Send("Type some text:")
|
c.Send("Type some text:")
|
||||||
msg, err := c.ReadTextMessage()
|
msg, err := c.ReadTextMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -111,7 +133,7 @@ var beh = tx.NewBehaviour().
|
||||||
)
|
)
|
||||||
|
|
||||||
func mutateMessage(fn func(string) string) tx.ActionFunc {
|
func mutateMessage(fn func(string) string) tx.ActionFunc {
|
||||||
return func(c *tx.Context) {
|
return func(c *tx.A) {
|
||||||
for {
|
for {
|
||||||
msg, err := c.ReadTextMessage()
|
msg, err := c.ReadTextMessage()
|
||||||
if err == tx.NotAvailableErr {
|
if err == tx.NotAvailableErr {
|
||||||
|
|
|
@ -1,18 +1,37 @@
|
||||||
package tx
|
package tx
|
||||||
|
|
||||||
// Implementing the intereface lets you
|
import (
|
||||||
// provide behaviour for the buttons etc.
|
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Update = apix.Update
|
||||||
|
|
||||||
|
// The argument for handling.
|
||||||
|
type Arg struct {
|
||||||
|
// Current context.
|
||||||
|
*Context
|
||||||
|
// The update that made the action to be called.
|
||||||
|
U *Update
|
||||||
|
}
|
||||||
|
type A = Arg
|
||||||
|
|
||||||
|
type GroupArg struct {
|
||||||
|
GroupArg *GroupContext
|
||||||
|
U *Update
|
||||||
|
}
|
||||||
|
type GA = GroupArg
|
||||||
|
|
||||||
type Action interface {
|
type Action interface {
|
||||||
Act(*Context)
|
Act(*Arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Customized action for the bot.
|
// Customized action for the bot.
|
||||||
type ActionFunc func(*Context)
|
type ActionFunc func(*Arg)
|
||||||
|
|
||||||
// The type implements changing screen to the underlying ScreenId
|
// The type implements changing screen to the underlying ScreenId
|
||||||
type ScreenChange ScreenId
|
type ScreenChange ScreenId
|
||||||
|
|
||||||
func (sc ScreenChange) Act(c *Context) {
|
func (sc ScreenChange) Act(c *Arg) {
|
||||||
if !c.B.ScreenExist(ScreenId(sc)) {
|
if !c.B.ScreenExist(ScreenId(sc)) {
|
||||||
panic(ScreenNotExistErr)
|
panic(ScreenNotExistErr)
|
||||||
}
|
}
|
||||||
|
@ -22,6 +41,6 @@ func (sc ScreenChange) Act(c *Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (af ActionFunc) Act(c *Context) {
|
func (af ActionFunc) Act(c *Arg) {
|
||||||
af(c)
|
af(c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ type Button struct {
|
||||||
Text string
|
Text string
|
||||||
Data string
|
Data string
|
||||||
Url string
|
Url string
|
||||||
|
SendLocation bool
|
||||||
Action Action
|
Action Action
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,26 +18,32 @@ type ButtonMap map[string]*Button
|
||||||
// Represents the reply button row.
|
// Represents the reply button row.
|
||||||
type ButtonRow []*Button
|
type ButtonRow []*Button
|
||||||
|
|
||||||
// Returns new button with specified text and action.
|
// Returns new button with the specified text and no action.
|
||||||
func NewButton() *Button {
|
func NewButton(text string) *Button {
|
||||||
return &Button{}
|
return &Button{
|
||||||
}
|
Text: text,
|
||||||
|
}
|
||||||
func (btn *Button) WithText(text string) *Button {
|
|
||||||
btn.Text = text
|
|
||||||
return btn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the URL for the button. Only for inline buttons.
|
||||||
func (btn *Button) WithUrl(url string) *Button {
|
func (btn *Button) WithUrl(url string) *Button {
|
||||||
btn.Url = url
|
btn.Url = url
|
||||||
return btn
|
return btn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the action when pressing the button.
|
||||||
|
// By default is nil and does nothing.
|
||||||
func (btn *Button) WithAction(a Action) *Button {
|
func (btn *Button) WithAction(a Action) *Button {
|
||||||
btn.Action = a
|
btn.Action = a
|
||||||
return btn
|
return btn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets whether the button must send owner's location.
|
||||||
|
func (btn *Button) WithSendLocation(ok bool) *Button {
|
||||||
|
btn.SendLocation = ok
|
||||||
|
return btn
|
||||||
|
}
|
||||||
|
|
||||||
func (btn *Button) ActionFunc(fn ActionFunc) *Button {
|
func (btn *Button) ActionFunc(fn ActionFunc) *Button {
|
||||||
return btn.WithAction(fn)
|
return btn.WithAction(fn)
|
||||||
}
|
}
|
||||||
|
@ -46,7 +53,11 @@ func (btn *Button) ScreenChange(sc ScreenChange) *Button {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (btn *Button) ToTelegram() apix.KeyboardButton {
|
func (btn *Button) ToTelegram() apix.KeyboardButton {
|
||||||
return apix.NewKeyboardButton(btn.Text)
|
ret := apix.NewKeyboardButton(btn.Text)
|
||||||
|
if btn.SendLocation {
|
||||||
|
ret.RequestLocation = true
|
||||||
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (btn *Button) ToTelegramInline() apix.InlineKeyboardButton {
|
func (btn *Button) ToTelegramInline() apix.InlineKeyboardButton {
|
||||||
|
|
|
@ -27,7 +27,7 @@ type GroupContext struct {
|
||||||
func (c *Context) handleUpdateChan(updates chan *Update) {
|
func (c *Context) handleUpdateChan(updates chan *Update) {
|
||||||
bot := c.B
|
bot := c.B
|
||||||
session := c.Session
|
session := c.Session
|
||||||
bot.Start.Act(c)
|
c.run(bot.Start, nil)
|
||||||
for u := range updates {
|
for u := range updates {
|
||||||
screen := bot.Screens[session.CurrentScreenId]
|
screen := bot.Screens[session.CurrentScreenId]
|
||||||
// The part is added to implement custom update handling.
|
// The part is added to implement custom update handling.
|
||||||
|
@ -45,12 +45,21 @@ func (c *Context) handleUpdateChan(updates chan *Update) {
|
||||||
btns := kbd.buttonMap()
|
btns := kbd.buttonMap()
|
||||||
text := u.Message.Text
|
text := u.Message.Text
|
||||||
btn, ok := btns[text]
|
btn, ok := btns[text]
|
||||||
// Sending wrong messages to
|
if !ok {
|
||||||
// the currently reading goroutine.
|
if u.Message.Location != nil {
|
||||||
if !ok && c.readingUpdate {
|
for _, b := range btns {
|
||||||
|
if b.SendLocation {
|
||||||
|
btn = b
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if c.readingUpdate {
|
||||||
|
// Skipping the update sending it to
|
||||||
|
// the reading goroutine.
|
||||||
c.updates <- u
|
c.updates <- u
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
act = btn.Action
|
act = btn.Action
|
||||||
|
@ -58,7 +67,7 @@ func (c *Context) handleUpdateChan(updates chan *Update) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if act != nil {
|
if act != nil {
|
||||||
c.run(act)
|
c.run(act, u)
|
||||||
}
|
}
|
||||||
} else if u.CallbackQuery != nil {
|
} else if u.CallbackQuery != nil {
|
||||||
cb := apix.NewCallback(u.CallbackQuery.ID, u.CallbackQuery.Data)
|
cb := apix.NewCallback(u.CallbackQuery.ID, u.CallbackQuery.Data)
|
||||||
|
@ -70,18 +79,22 @@ func (c *Context) handleUpdateChan(updates chan *Update) {
|
||||||
}
|
}
|
||||||
kbd := bot.Keyboards[screen.InlineKeyboardId]
|
kbd := bot.Keyboards[screen.InlineKeyboardId]
|
||||||
btns := kbd.buttonMap()
|
btns := kbd.buttonMap()
|
||||||
btn := btns[data]
|
btn, ok := btns[data]
|
||||||
btn.Action.Act(c)
|
if !ok && c.readingUpdate {
|
||||||
|
c.updates <- u
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.run(btn.Action, u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) run(a Action) {
|
func (c *Context) run(a Action, u *Update) {
|
||||||
go a.Act(c)
|
go a.Act(&A{c, u})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes screen of user to the Id one.
|
// Changes screen of user to the Id one.
|
||||||
func (c *Context) ChangeScreen(screenId ScreenId) error {
|
func (c *Arg) ChangeScreen(screenId ScreenId) error {
|
||||||
// Return if it will not change anything.
|
// Return if it will not change anything.
|
||||||
if c.CurrentScreenId == screenId {
|
if c.CurrentScreenId == screenId {
|
||||||
return nil
|
return nil
|
||||||
|
@ -97,13 +110,13 @@ func (c *Context) ChangeScreen(screenId ScreenId) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
screen := c.B.Screens[screenId]
|
screen := c.B.Screens[screenId]
|
||||||
screen.Render(c)
|
screen.Render(c.Context)
|
||||||
|
|
||||||
c.Session.ChangeScreen(screenId)
|
c.Session.ChangeScreen(screenId)
|
||||||
c.KeyboardId = screen.KeyboardId
|
c.KeyboardId = screen.KeyboardId
|
||||||
|
|
||||||
if screen.Action != nil {
|
if screen.Action != nil {
|
||||||
c.run(screen.Action)
|
c.run(screen.Action, c.U)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
package tx
|
package tx
|
||||||
|
|
||||||
import (
|
|
||||||
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Update = apix.Update
|
|
||||||
|
|
||||||
// Represents unique value to identify chats.
|
// Represents unique value to identify chats.
|
||||||
// In fact is simply ID of the chat.
|
// In fact is simply ID of the chat.
|
||||||
type SessionId int64
|
type SessionId int64
|
||||||
|
|
Loading…
Reference in a new issue