Finished the node approach to the screens.

This commit is contained in:
Andrey Parhomenko 2023-09-21 14:54:31 +03:00
parent 061add76a8
commit 7d149558f9
6 changed files with 81 additions and 60 deletions

View file

@ -52,6 +52,11 @@ func ExtractSessionData(c *tg.Context) *SessionData {
var ( var (
startScreenButton = tg.NewButton("Home").Go("/") startScreenButton = tg.NewButton("Home").Go("/")
backButton = tg.NewButton("Back").Go("..")
backKeyboard = tg.NewKeyboard().Row(
backButton,
)
incDecKeyboard = tg.NewKeyboard().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)
@ -70,10 +75,7 @@ var (
navKeyboard = tg.NewKeyboard().Row( navKeyboard = tg.NewKeyboard().Row(
tg.NewButton("Inc/Dec").Go("/inc-dec"), tg.NewButton("Inc/Dec").Go("/inc-dec"),
).Row( ).Row(
tg.NewButton("Upper case").ActionFunc(func(c *tg.Context){ tg.NewButton("Mutate messages").Go("/mutate-messages"),
c.Go("/upper-case", "this shit", "works")
}),
tg.NewButton("Lower case").Go("/case"),
).Row( ).Row(
tg.NewButton("Send location").Go("/send-location"), tg.NewButton("Send location").Go("/send-location"),
).Reply().WithOneTime(true) ).Reply().WithOneTime(true)
@ -119,6 +121,37 @@ WithInitFunc(func(c *tg.Context) {
navKeyboard.Widget("Choose what you are interested in"), navKeyboard.Widget("Choose what you are interested in"),
), ),
tg.NewNode(
"mutate-messages", tg.NewPage().WithReply(
tg.NewKeyboard().Row(
tg.NewButton("Upper case").Go("upper-case"),
tg.NewButton("Lower case").Go("lower-case"),
).Row(
backButton,
).Reply().Widget(
"Choose the function to mutate string",
),
),
tg.NewNode(
"upper-case", tg.NewPage().WithReply(
backKeyboard.Reply().Widget(
"Type a string and the bot will convert it to upper case",
),
).WithSub(
NewMutateMessageWidget(strings.ToUpper),
),
),
tg.NewNode(
"lower-case", tg.NewPage().WithReply(
backKeyboard.Reply().Widget(
"Type a string and the bot will convert it to lower case",
),
).WithSub(
NewMutateMessageWidget(strings.ToLower),
),
),
),
tg.NewNode( tg.NewNode(
"inc-dec", tg.NewPage().WithReply( "inc-dec", tg.NewPage().WithReply(
incDecKeyboard.Reply().Widget("Press the buttons to increment and decrement"), incDecKeyboard.Reply().Widget("Press the buttons to increment and decrement"),
@ -129,26 +162,6 @@ WithInitFunc(func(c *tg.Context) {
}), }),
), ),
tg.NewNode(
"upper-case", tg.NewPage().WithText(
"Type text and the bot will send you the upper case version to you",
).WithReply(
navToStartKeyboard.Widget(""),
).WithSub(
NewMutateMessageWidget(strings.ToUpper),
),
),
tg.NewNode(
"lower-case", tg.NewPage().WithText(
"Type text and the bot will send you the lower case version",
).WithReply(
navToStartKeyboard.Widget(""),
).WithSub(
NewMutateMessageWidget(strings.ToLower),
),
),
tg.NewNode( tg.NewNode(
"send-location", tg.NewPage().WithReply( "send-location", tg.NewPage().WithReply(
sendLocationKeyboard.Widget("Press the button to send your location!"), sendLocationKeyboard.Widget("Press the button to send your location!"),
@ -169,8 +182,7 @@ WithInitFunc(func(c *tg.Context) {
tg.NewCommand("start"). tg.NewCommand("start").
Desc("start or restart the bot or move to the start screen"). Desc("start or restart the bot or move to the start screen").
ActionFunc(func(c *tg.Context){ ActionFunc(func(c *tg.Context){
c.Sendf("Your username is %q", c.Message.From.UserName) c.Go("/")
c.Go("/start")
}), }),
tg.NewCommand("hello"). tg.NewCommand("hello").
Desc("sends the 'Hello, World!' message back"). Desc("sends the 'Hello, World!' message back").
@ -227,7 +239,6 @@ func main() {
} }
bot = bot. bot = bot.
WithBehaviour(beh). WithBehaviour(beh).
WithGroupBehaviour(gBeh).
Debug(true) Debug(true)
bot.Data = &BotData{ bot.Data = &BotData{

View file

@ -63,8 +63,11 @@ func (btn *Button) ActionFunc(fn ActionFunc) *Button {
return btn.WithAction(fn) return btn.WithAction(fn)
} }
func (btn *Button) Go(sc ScreenChange) *Button { func (btn *Button) Go(pth Path, args ...any) *Button {
return btn.WithAction(sc) return btn.WithAction(ScreenGo{
Path: pth,
Args: args,
})
} }
func (btn *Button) ToTelegram() apix.KeyboardButton { func (btn *Button) ToTelegram() apix.KeyboardButton {

View file

@ -13,7 +13,7 @@ var (
func initEncoding() { func initEncoding() {
actions := map[string]Action{ actions := map[string]Action{
"action-func": ActionFunc(nil), "action-func": ActionFunc(nil),
"screen-change": ScreenChange(""), "screen-change": ScreenGo{},
} }
for k, action := range actions { for k, action := range actions {
DefineAction(k, action) DefineAction(k, action)

View file

@ -143,33 +143,22 @@ func (af ActionFunc) Act(c *Context) {
af(c) af(c)
} }
// The type implements changing screen to the underlying ScreenId
type ScreenChange Path
func (sc ScreenChange) Act(c *Context) {
if !c.Bot.behaviour.PathExist(Path(sc)) {
panic(ScreenNotExistErr)
}
err := c.Go(Path(sc))
if err != nil {
panic(err)
}
}
type C = Context type C = Context
// Changes screen of user to the Id one. // Changes screen of user to the Id one.
func (c *Context) Go(pth Path, args ...any) error { func (c *Context) Go(pth Path, args ...any) error {
if !c.PathExist(pth) {
return ScreenNotExistErr
}
// Getting the screen and changing to // Getting the screen and changing to
// then executing its widget. // then executing its widget.
if !pth.IsAbs() { if !pth.IsAbs() {
pth = (c.Path() + "/" + pth).Clean() pth = (c.Path() + "/" + pth).Clean()
} }
c.Sendf("path: %q\nmap: %v", pth, c.Bot.behaviour.Screens)
if !c.PathExist(pth) {
return ScreenNotExistErr
}
c.prevPath = c.path c.prevPath = c.path
c.path = pth c.path = pth
@ -217,16 +206,6 @@ func (c *Context) RunWidget(widget Widget, args ...any) *UpdateChan {
return updates return updates
} }
// Go to the root screen.
func (c *Context) GoRoot() {
c.Go("/")
}
// Go one level upper in the screen hierarchy.
func (c *Context) GoUp() {
c.Go(c.Path().Dir())
}
// Change screen to the previous. // Change screen to the previous.
// To get to the parent screen use GoUp. // To get to the parent screen use GoUp.
func (c *Context) GoPrev() { func (c *Context) GoPrev() {

View file

@ -4,6 +4,24 @@ import (
"path" "path"
) )
// The type implements changing screen to the underlying ScreenId
type ScreenGo struct {
Path Path
Args []any
}
func (sc ScreenGo) Act(c *Context) {
err := c.Go(sc.Path, sc.Args...)
if err != nil {
panic(err)
}
}
// The same as Act.
func (sc ScreenGo) Serve(c *Context) {
sc.Act(c)
}
// Unique identifier for the screen // Unique identifier for the screen
// and relative paths to the screen. // and relative paths to the screen.
type Path string type Path string
@ -89,7 +107,7 @@ func (n *Node) ScreenMap(root Path) ScreenMap {
pth := (root + n.Path).Clean() pth := (root + n.Path).Clean()
m[pth] = n.Screen m[pth] = n.Screen
for _, sub := range n.Subs { for _, sub := range n.Subs {
buf := sub.ScreenMap((pth + "/").Clean()) buf := sub.ScreenMap(pth + "/")
for k, v := range buf { for k, v := range buf {
_, ok := m[k] _, ok := m[k]
if ok { if ok {

View file

@ -20,11 +20,11 @@ type Widget interface {
Serve(*Context) Serve(*Context)
} }
// Needs implementation. // Implementing the interface provides ability to
// Behaviour can be the root widget or something like // be used as the root widget for contexts.
// that.
type RootWidget interface { type RootWidget interface {
Widget Widget
SetSub(Widget)
} }
// Implementing the interface provides way // Implementing the interface provides way
@ -36,6 +36,15 @@ type Filterer interface {
Filter(*Update, MessageMap) bool Filter(*Update, MessageMap) bool
} }
// General type function for faster typing.
type Func func(*Context)
func (f Func) Act(c *Context) {
f(c)
}
func (f Func) Serve(c *Context) {
f(c)
}
// The type represents general update channel. // The type represents general update channel.
type UpdateChan struct { type UpdateChan struct {
chn chan *Update chn chan *Update
@ -48,6 +57,7 @@ func NewUpdateChan() *UpdateChan {
return ret return ret
} }
func (updates *UpdateChan) Chan() chan *Update { func (updates *UpdateChan) Chan() chan *Update {
return updates.chn return updates.chn
} }