Implemented rendering also for the inline keyboards.
This commit is contained in:
parent
c537ccdec1
commit
6dd954e8ad
9 changed files with 159 additions and 45 deletions
|
@ -8,8 +8,18 @@ package behx
|
||||||
type Behaviour struct {
|
type Behaviour struct {
|
||||||
Start Action
|
Start Action
|
||||||
Screens ScreenMap
|
Screens ScreenMap
|
||||||
|
Keyboards KeyboardMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewBehaviour(
|
||||||
|
start Action,
|
||||||
|
screens ScreenMap,
|
||||||
|
keyboards KeyboardMap,
|
||||||
|
) *Behaviour {
|
||||||
|
return &Behaviour{
|
||||||
|
start, screens, keyboards,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check whether the screen exists in the behaviour.
|
// Check whether the screen exists in the behaviour.
|
||||||
func (beh *Behaviour) ScreenExists(id ScreenId) bool {
|
func (beh *Behaviour) ScreenExists(id ScreenId) bool {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package behx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The wrapper around Telegram API.
|
// The wrapper around Telegram API.
|
||||||
|
@ -66,7 +67,10 @@ func (bot *Bot) Run() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
screen := bot.Screens[session.CurrentScreenId]
|
screen := bot.Screens[session.CurrentScreenId]
|
||||||
screen.Render(ctx)
|
err := screen.Render(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("screen rendering:", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -6,7 +6,9 @@ import (
|
||||||
|
|
||||||
// The type wraps Telegram API's button to provide Action functionality.
|
// The type wraps Telegram API's button to provide Action functionality.
|
||||||
type Button struct {
|
type Button struct {
|
||||||
apix.KeyboardButton
|
Text string
|
||||||
|
Data string
|
||||||
|
Url string
|
||||||
Action Action
|
Action Action
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,11 +20,45 @@ type ButtonRow []*Button
|
||||||
// Returns new button with specified text and action.
|
// Returns new button with specified text and action.
|
||||||
func NewButton(text string, action Action) *Button {
|
func NewButton(text string, action Action) *Button {
|
||||||
return &Button{
|
return &Button{
|
||||||
KeyboardButton: apix.NewKeyboardButton(text),
|
Text: text,
|
||||||
Action: action,
|
Action: action,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewButtonData(text string, data string, action Action) *Button {
|
||||||
|
return &Button{
|
||||||
|
Text: text,
|
||||||
|
Data: data,
|
||||||
|
Action: action,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewButtonUrl(text string, url string, action Action) *Button {
|
||||||
|
return &Button{
|
||||||
|
Text: text,
|
||||||
|
Url: url,
|
||||||
|
Action: action,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (btn *Button) ToTelegram() apix.KeyboardButton {
|
||||||
|
return apix.NewKeyboardButton(btn.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (btn *Button) ToTelegramInline() apix.InlineKeyboardButton {
|
||||||
|
if btn.Data != "" {
|
||||||
|
return apix.NewInlineKeyboardButtonData(btn.Text, btn.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if btn.Url != "" {
|
||||||
|
return apix.NewInlineKeyboardButtonURL(btn.Text, btn.Url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no match then return the data one with data the same as the text.
|
||||||
|
return apix.NewInlineKeyboardButtonData(btn.Text, btn.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func NewButtonRow(btns ...*Button) ButtonRow {
|
func NewButtonRow(btns ...*Button) ButtonRow {
|
||||||
return btns
|
return btns
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ func (c *Context) ChangeScreen(screenId ScreenId) error {
|
||||||
|
|
||||||
// Sends to the user specified text.
|
// Sends to the user specified text.
|
||||||
func (c *Context) Send(text string) error {
|
func (c *Context) Send(text string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,7 @@ import (
|
||||||
var (
|
var (
|
||||||
ScreenNotExistErr = errors.New("screen does not exist")
|
ScreenNotExistErr = errors.New("screen does not exist")
|
||||||
SessionNotExistErr = errors.New("session does not exist")
|
SessionNotExistErr = errors.New("session does not exist")
|
||||||
|
KeyboardNotExistErr = errors.New("keyboard does not exist")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,16 @@ var otherKeyboard = tgbotapi.NewReplyKeyboard(
|
||||||
),
|
),
|
||||||
)*/
|
)*/
|
||||||
|
|
||||||
|
type KeyboardId string
|
||||||
|
|
||||||
// The type represents reply keyboard which
|
// The type represents reply keyboard which
|
||||||
// is supposed to be showed on a Screen.
|
// is supposed to be showed on a Screen.
|
||||||
type Keyboard struct {
|
type Keyboard struct {
|
||||||
Rows []ButtonRow
|
Rows []ButtonRow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type KeyboardMap map[KeyboardId] *Keyboard
|
||||||
|
|
||||||
// Return the new reply keyboard with rows as specified.
|
// Return the new reply keyboard with rows as specified.
|
||||||
func NewKeyboard(rows ...ButtonRow) *Keyboard {
|
func NewKeyboard(rows ...ButtonRow) *Keyboard {
|
||||||
return &Keyboard{
|
return &Keyboard{
|
||||||
|
@ -36,7 +40,7 @@ func (kbd *Keyboard) ToTelegram() apix.ReplyKeyboardMarkup {
|
||||||
for _, row := range kbd.Rows {
|
for _, row := range kbd.Rows {
|
||||||
buttons := []apix.KeyboardButton{}
|
buttons := []apix.KeyboardButton{}
|
||||||
for _, button := range row {
|
for _, button := range row {
|
||||||
buttons = append(buttons, apix.NewKeyboardButton(button.Text))
|
buttons = append(buttons, button.ToTelegram())
|
||||||
}
|
}
|
||||||
rows = append(rows, buttons)
|
rows = append(rows, buttons)
|
||||||
}
|
}
|
||||||
|
@ -44,6 +48,19 @@ func (kbd *Keyboard) ToTelegram() apix.ReplyKeyboardMarkup {
|
||||||
return apix.NewReplyKeyboard(rows...)
|
return apix.NewReplyKeyboard(rows...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (kbd *Keyboard) ToTelegramInline() apix.InlineKeyboardMarkup {
|
||||||
|
rows := [][]apix.InlineKeyboardButton{}
|
||||||
|
for _, row := range kbd.Rows {
|
||||||
|
buttons := []apix.InlineKeyboardButton{}
|
||||||
|
for _, button := range row {
|
||||||
|
buttons = append(buttons, button.ToTelegramInline())
|
||||||
|
}
|
||||||
|
rows = append(rows, buttons)
|
||||||
|
}
|
||||||
|
|
||||||
|
return apix.NewInlineKeyboardMarkup(rows...)
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the map of buttons. Used to define the Action.
|
// Returns the map of buttons. Used to define the Action.
|
||||||
func (kbd *Keyboard) buttonMap() ButtonMap {
|
func (kbd *Keyboard) buttonMap() ButtonMap {
|
||||||
ret := make(ButtonMap)
|
ret := make(ButtonMap)
|
||||||
|
|
|
@ -16,20 +16,23 @@ type ScreenText string
|
||||||
type Screen struct {
|
type Screen struct {
|
||||||
// Text to be sent to the user when changing to the screen.
|
// Text to be sent to the user when changing to the screen.
|
||||||
Text ScreenText
|
Text ScreenText
|
||||||
// Keyboard to be displayed on the screen.
|
|
||||||
Keyboard *Keyboard
|
|
||||||
// The keyboard to be sent in the message part.
|
// The keyboard to be sent in the message part.
|
||||||
InlineKeyboard *Keyboard
|
InlineKeyboardId KeyboardId
|
||||||
|
|
||||||
|
// Keyboard to be displayed on the screen.
|
||||||
|
KeyboardId KeyboardId
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map structure for the screens.
|
// Map structure for the screens.
|
||||||
type ScreenMap map[ScreenId] *Screen
|
type ScreenMap map[ScreenId] *Screen
|
||||||
|
|
||||||
// Returns the new screen with specified Text and Keyboard.
|
// Returns the new screen with specified Text and Keyboard.
|
||||||
func NewScreen(text ScreenText, kbd *Keyboard) *Screen {
|
func NewScreen(text ScreenText, ikbd KeyboardId, kbd KeyboardId) *Screen {
|
||||||
return &Screen {
|
return &Screen {
|
||||||
Text: text,
|
Text: text,
|
||||||
Keyboard: kbd,
|
InlineKeyboardId: ikbd,
|
||||||
|
KeyboardId: kbd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,25 +42,40 @@ func (st ScreenText) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renders output of the screen to the side of the user.
|
// Renders output of the screen to the side of the user.
|
||||||
func (s *Screen) Render(c *Context) {
|
func (s *Screen) Render(c *Context) error {
|
||||||
id := c.S.Id.ToTelegram()
|
id := c.S.Id.ToTelegram()
|
||||||
|
|
||||||
msg := apix.NewMessage(id, s.Text.String())
|
msg := apix.NewMessage(id, s.Text.String())
|
||||||
|
|
||||||
// First sending the inline keyboard.
|
if s.InlineKeyboardId != "" {
|
||||||
if s.InlineKeyboard != nil {
|
kbd, ok := c.B.Keyboards[s.InlineKeyboardId]
|
||||||
msg.ReplyMarkup = s.InlineKeyboard.ToTelegram()
|
if !ok {
|
||||||
if _, err := c.B.Send(msg) ; err != nil {
|
return KeyboardNotExistErr
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
msg.ReplyMarkup = kbd.ToTelegramInline()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then sending the screen one.
|
_, err := c.B.Send(msg)
|
||||||
if s.Keyboard != nil {
|
if err != nil {
|
||||||
msg = apix.NewMessage(id, "check")
|
return err
|
||||||
msg.ReplyMarkup = s.Keyboard.ToTelegram()
|
|
||||||
if _, err := c.B.Send(msg) ; err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.KeyboardId != "" {
|
||||||
|
msg = apix.NewMessage(id, ">")
|
||||||
|
|
||||||
|
kbd, ok := c.B.Keyboards[s.KeyboardId]
|
||||||
|
if !ok {
|
||||||
|
return KeyboardNotExistErr
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.ReplyMarkup = kbd.ToTelegram()
|
||||||
|
if _, err := c.B.Send(msg) ; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ type Session struct {
|
||||||
Id SessionId
|
Id SessionId
|
||||||
CurrentScreenId ScreenId
|
CurrentScreenId ScreenId
|
||||||
PreviousScreenId ScreenId
|
PreviousScreenId ScreenId
|
||||||
|
KeyboardId KeyboardId
|
||||||
}
|
}
|
||||||
|
|
||||||
// The type represents map of sessions using
|
// The type represents map of sessions using
|
||||||
|
|
|
@ -8,34 +8,61 @@ import (
|
||||||
"boteval/src/behx"
|
"boteval/src/behx"
|
||||||
)
|
)
|
||||||
|
|
||||||
var startScreen = behx.NewScreen(
|
var rootKbd = behx.NewKeyboard(
|
||||||
"Hello, World!",
|
behx.NewButtonRow(
|
||||||
behx.NewKeyboard(
|
behx.NewButton(
|
||||||
behx.NewButtonRow(
|
"PRESS ME",
|
||||||
behx.NewButton(
|
behx.NewCustomAction(func(c *behx.Context){
|
||||||
"PRESS ME",
|
log.Println("pressed the button!")
|
||||||
behx.NewCustomAction(func(c *behx.Context){
|
}),
|
||||||
log.Println("pressed the button!")
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
behx.NewButton("PRESS ME 2", behx.NewCustomAction(func(c *behx.Context){
|
|
||||||
log.Println("pressed another button!")
|
|
||||||
})),
|
|
||||||
),
|
|
||||||
behx.NewButtonRow(
|
|
||||||
behx.NewButton("PRESS ME 3", behx.NewCustomAction(func(c *behx.Context){
|
|
||||||
log.Println("pressed third button!")
|
|
||||||
})),
|
|
||||||
),
|
),
|
||||||
|
behx.NewButton("PRESS ME 2", behx.NewCustomAction(func(c *behx.Context){
|
||||||
|
log.Println("pressed another button!")
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
behx.NewButtonRow(
|
||||||
|
behx.NewButton("PRESS ME 3", behx.NewCustomAction(func(c *behx.Context){
|
||||||
|
log.Println("pressed third button!")
|
||||||
|
})),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
var behaviour = &behx.Behaviour{
|
var inlineKbd = behx.NewKeyboard(
|
||||||
Start: behx.NewScreenChange("start"),
|
behx.NewButtonRow(
|
||||||
Screens: behx.ScreenMap{
|
behx.NewButton(
|
||||||
|
"INLINE PRESS ME",
|
||||||
|
behx.NewCustomAction(func(c *behx.Context){
|
||||||
|
log.Println("INLINE pressed the button!")
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
behx.NewButton("INLINE PRESS ME 2", behx.NewCustomAction(func(c *behx.Context){
|
||||||
|
log.Println("INLINE pressed another button!")
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
behx.NewButtonRow(
|
||||||
|
behx.NewButton("INLINE PRESS ME 3", behx.NewCustomAction(func(c *behx.Context){
|
||||||
|
log.Println("INLINE pressed third button!")
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
var startScreen = behx.NewScreen(
|
||||||
|
"Hello, World!",
|
||||||
|
"inline",
|
||||||
|
"root",
|
||||||
|
)
|
||||||
|
|
||||||
|
var behaviour = behx.NewBehaviour(
|
||||||
|
behx.NewScreenChange("start"),
|
||||||
|
behx.ScreenMap{
|
||||||
"start": startScreen,
|
"start": startScreen,
|
||||||
},
|
},
|
||||||
}
|
behx.KeyboardMap{
|
||||||
|
"root": rootKbd,
|
||||||
|
"inline": inlineKbd,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
token := os.Getenv("BOT_TOKEN")
|
token := os.Getenv("BOT_TOKEN")
|
||||||
|
|
Loading…
Reference in a new issue