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 (
startScreenButton = tg.NewButton("Home").Go("/")
backButton = tg.NewButton("Back").Go("..")
backKeyboard = tg.NewKeyboard().Row(
backButton,
)
incDecKeyboard = tg.NewKeyboard().Row(
tg.NewButton("+").ActionFunc(func(c *tg.Context) {
d := ExtractSessionData(c)
@ -70,10 +75,7 @@ var (
navKeyboard = tg.NewKeyboard().Row(
tg.NewButton("Inc/Dec").Go("/inc-dec"),
).Row(
tg.NewButton("Upper case").ActionFunc(func(c *tg.Context){
c.Go("/upper-case", "this shit", "works")
}),
tg.NewButton("Lower case").Go("/case"),
tg.NewButton("Mutate messages").Go("/mutate-messages"),
).Row(
tg.NewButton("Send location").Go("/send-location"),
).Reply().WithOneTime(true)
@ -119,6 +121,37 @@ WithInitFunc(func(c *tg.Context) {
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(
"inc-dec", tg.NewPage().WithReply(
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(
"send-location", tg.NewPage().WithReply(
sendLocationKeyboard.Widget("Press the button to send your location!"),
@ -169,8 +182,7 @@ WithInitFunc(func(c *tg.Context) {
tg.NewCommand("start").
Desc("start or restart the bot or move to the start screen").
ActionFunc(func(c *tg.Context){
c.Sendf("Your username is %q", c.Message.From.UserName)
c.Go("/start")
c.Go("/")
}),
tg.NewCommand("hello").
Desc("sends the 'Hello, World!' message back").
@ -227,7 +239,6 @@ func main() {
}
bot = bot.
WithBehaviour(beh).
WithGroupBehaviour(gBeh).
Debug(true)
bot.Data = &BotData{

View file

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

View file

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

View file

@ -143,33 +143,22 @@ func (af ActionFunc) Act(c *Context) {
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
// Changes screen of user to the Id one.
func (c *Context) Go(pth Path, args ...any) error {
if !c.PathExist(pth) {
return ScreenNotExistErr
}
// Getting the screen and changing to
// then executing its widget.
if !pth.IsAbs() {
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.path = pth
@ -217,16 +206,6 @@ func (c *Context) RunWidget(widget Widget, args ...any) *UpdateChan {
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.
// To get to the parent screen use GoUp.
func (c *Context) GoPrev() {

View file

@ -4,6 +4,24 @@ import (
"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
// and relative paths to the screen.
type Path string
@ -89,7 +107,7 @@ func (n *Node) ScreenMap(root Path) ScreenMap {
pth := (root + n.Path).Clean()
m[pth] = n.Screen
for _, sub := range n.Subs {
buf := sub.ScreenMap((pth + "/").Clean())
buf := sub.ScreenMap(pth + "/")
for k, v := range buf {
_, ok := m[k]
if ok {

View file

@ -20,11 +20,11 @@ type Widget interface {
Serve(*Context)
}
// Needs implementation.
// Behaviour can be the root widget or something like
// that.
// Implementing the interface provides ability to
// be used as the root widget for contexts.
type RootWidget interface {
Widget
SetSub(Widget)
}
// Implementing the interface provides way
@ -36,6 +36,15 @@ type Filterer interface {
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.
type UpdateChan struct {
chn chan *Update
@ -48,6 +57,7 @@ func NewUpdateChan() *UpdateChan {
return ret
}
func (updates *UpdateChan) Chan() chan *Update {
return updates.chn
}