Keep implementing the new UI system.
This commit is contained in:
parent
1f52474082
commit
abf080164a
11 changed files with 145 additions and 133 deletions
|
@ -103,15 +103,14 @@ WithInitFunc(func(c *tg.Context) {
|
||||||
c.Session.Data = &SessionData{}
|
c.Session.Data = &SessionData{}
|
||||||
}).WithRootNode(tg.NewRootNode(
|
}).WithRootNode(tg.NewRootNode(
|
||||||
// The "/" widget.
|
// The "/" widget.
|
||||||
tg.WidgetFunc(func(c *tg.Context) tg.UIs {
|
tg.WidgetFunc(func(c *tg.Context) tg.UIs {return tg.UIs{
|
||||||
return tg.UIs{
|
|
||||||
|
|
||||||
tg.NewKeyboard().Row(
|
tg.NewKeyboard().Row(
|
||||||
tg.NewButton("GoT Github page").
|
tg.NewButton("GoT Github page").
|
||||||
WithUrl("https://github.com/mojosa-software/got"),
|
WithUrl("https://github.com/mojosa-software/got"),
|
||||||
).Inline().Widget(
|
).Inline().Widget(
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"Hello, %s"
|
"Hello, %s!\n"
|
||||||
"The testing bot started!\n",
|
"The testing bot started!\n",
|
||||||
"You can see the basics of usage in the ",
|
"You can see the basics of usage in the ",
|
||||||
"cmd/test/main.go file!",
|
"cmd/test/main.go file!",
|
||||||
|
@ -129,8 +128,7 @@ WithInitFunc(func(c *tg.Context) {
|
||||||
"Choose the point of your interest",
|
"Choose the point of your interest",
|
||||||
),
|
),
|
||||||
|
|
||||||
}
|
}}),
|
||||||
)
|
|
||||||
|
|
||||||
tg.NewNode(
|
tg.NewNode(
|
||||||
"mutate-messages", tg.NewPage().WithReply(
|
"mutate-messages", tg.NewPage().WithReply(
|
||||||
|
|
80
tg/bot.go
80
tg/bot.go
|
@ -25,9 +25,9 @@ type Bot struct {
|
||||||
groupBehaviour *GroupBehaviour
|
groupBehaviour *GroupBehaviour
|
||||||
// Bot behaviour in channels.
|
// Bot behaviour in channels.
|
||||||
channelBehaviour *ChannelBehaviour
|
channelBehaviour *ChannelBehaviour
|
||||||
|
contexts map[SessionId] *context
|
||||||
sessions SessionMap
|
sessions SessionMap
|
||||||
groupSessions GroupSessionMap
|
groupSessions GroupSessionMap
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the new bot with empty sessions and behaviour.
|
// Return the new bot with empty sessions and behaviour.
|
||||||
|
@ -50,8 +50,13 @@ func (bot *Bot) Debug(debug bool) *Bot {
|
||||||
// Send the Renderable to the specified session client side.
|
// Send the Renderable to the specified session client side.
|
||||||
// Can be used for both group and private sessions.
|
// Can be used for both group and private sessions.
|
||||||
func (bot *Bot) Send(
|
func (bot *Bot) Send(
|
||||||
sid SessionId, v Renderable,
|
sid SessionId, v Sendable,
|
||||||
) (*Message, error) {
|
) (*Message, error) {
|
||||||
|
c, ok := bot.contexts[sid]
|
||||||
|
if !ok {
|
||||||
|
return nil, ContextNotExistErr
|
||||||
|
}
|
||||||
|
|
||||||
config := v.Render(sid, bot)
|
config := v.Render(sid, bot)
|
||||||
if config.Error != nil {
|
if config.Error != nil {
|
||||||
return nil, config.Error
|
return nil, config.Error
|
||||||
|
@ -64,7 +69,7 @@ func (bot *Bot) Send(
|
||||||
return &msg, nil
|
return &msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bot *Bot) Render(
|
/*func (bot *Bot) Render(
|
||||||
sid SessionId, r Renderable,
|
sid SessionId, r Renderable,
|
||||||
) (MessageMap, error) {
|
) (MessageMap, error) {
|
||||||
configs := r.Render(sid, bot)
|
configs := r.Render(sid, bot)
|
||||||
|
@ -84,7 +89,7 @@ func (bot *Bot) Render(
|
||||||
messages[config.Name] = &msg
|
messages[config.Name] = &msg
|
||||||
}
|
}
|
||||||
return messages, nil
|
return messages, nil
|
||||||
}
|
}*/
|
||||||
|
|
||||||
func (bot *Bot) GetSession(
|
func (bot *Bot) GetSession(
|
||||||
sid SessionId,
|
sid SessionId,
|
||||||
|
@ -210,57 +215,40 @@ func (bot *Bot) Run() error {
|
||||||
// The function handles updates supposed for the private
|
// The function handles updates supposed for the private
|
||||||
// chat with the bot.
|
// chat with the bot.
|
||||||
func (bot *Bot) handlePrivate(updates chan *Update) {
|
func (bot *Bot) handlePrivate(updates chan *Update) {
|
||||||
chans := make(map[SessionId] *UpdateChan )
|
|
||||||
var sid SessionId
|
var sid SessionId
|
||||||
for u := range updates {
|
for u := range updates {
|
||||||
sid = SessionId(u.FromChat().ID)
|
sid = SessionId(u.FromChat().ID)
|
||||||
// Create new session if the one does not exist
|
ctx, ctxOk := bot.contexts[sid]
|
||||||
// for this user.
|
if u.Message != nil && !ctxOk {
|
||||||
|
// Create context on any message
|
||||||
// Making the bot ignore anything except "start"
|
// if we have no one.
|
||||||
// before the session started
|
|
||||||
session, sessionOk := bot.sessions[sid]
|
session, sessionOk := bot.sessions[sid]
|
||||||
chn, chnOk := chans[sid]
|
if !sessionOk {
|
||||||
if sessionOk {
|
// Creating session if we have none.
|
||||||
// Creating new goroutine for
|
session = bot.sessions.Add(sid)
|
||||||
// the session that exists
|
}
|
||||||
// but has none.
|
session = bot.sessions[sid]
|
||||||
if !chnOk {
|
ctx = &context{
|
||||||
ctx := &context{
|
|
||||||
Bot: bot,
|
Bot: bot,
|
||||||
Session: session,
|
Session: session,
|
||||||
|
scope: PrivateContextScope,
|
||||||
|
updates: NewUpdateChan(),
|
||||||
}
|
}
|
||||||
chn := NewUpdateChan()
|
if !ctxOk {
|
||||||
chans[sid] = chn
|
bot.contexts[sid] = ctx
|
||||||
go (&Context{
|
|
||||||
context: ctx,
|
|
||||||
Update: u,
|
|
||||||
input: chn,
|
|
||||||
}).serve()
|
|
||||||
}
|
|
||||||
} else if u.Message != nil {
|
|
||||||
// Create session on any message
|
|
||||||
// if we have no one.
|
|
||||||
bot.sessions.Add(sid)
|
|
||||||
lsession := bot.sessions[sid]
|
|
||||||
ctx := &context{
|
|
||||||
Bot: bot,
|
|
||||||
Session: lsession,
|
|
||||||
}
|
|
||||||
chn := NewUpdateChan()
|
|
||||||
chans[sid] = chn
|
|
||||||
go (&Context{
|
|
||||||
context: ctx,
|
|
||||||
Update: u,
|
|
||||||
input: chn,
|
|
||||||
}).serve()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chn, ok := chans[sid]
|
go (&Context{
|
||||||
// The bot MUST get the "start" command.
|
context: ctx,
|
||||||
// It will do nothing otherwise.
|
Update: u,
|
||||||
if ok {
|
input: ctx.updates,
|
||||||
chn.Send(u)
|
}).serve()
|
||||||
|
ctx.updates.Send(u)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctxOk {
|
||||||
|
ctx.updates.Send(u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ func (c *Command) WithWidget(w Widget) *Command {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Command) WidgetFunc(fn WidgetFunc) *Command {
|
func (c *Command) WidgetFunc(fn Func) *Command {
|
||||||
return c.WithWidget(fn)
|
return c.WithWidget(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ func (widget *CommandWidget) Serve(c *Context) {
|
||||||
c.Run(cmd.Action, u)
|
c.Run(cmd.Action, u)
|
||||||
if cmd.Widget != nil {
|
if cmd.Widget != nil {
|
||||||
cmdUpdates.Close()
|
cmdUpdates.Close()
|
||||||
cmdUpdates = c.RunWidget(cmd.Widget)
|
cmdUpdates = c.runWidget(cmd.Widget)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
26
tg/compo.go
26
tg/compo.go
|
@ -1,32 +1,34 @@
|
||||||
package tg
|
package tg
|
||||||
|
|
||||||
type UIs []UI
|
|
||||||
|
|
||||||
// The type describes dynamic screen widget.
|
// The type describes dynamic screen widget
|
||||||
|
// That can have multiple UI components.
|
||||||
type Widget interface {
|
type Widget interface {
|
||||||
UIs(*Context) UIs
|
Render(*Context) UI
|
||||||
}
|
}
|
||||||
|
|
||||||
// The way to describe custom function based Widgets.
|
// The way to describe custom function based Widgets.
|
||||||
type WidgetFunc func(c *Context) UIs
|
type RenderFunc func(c *Context) UI
|
||||||
func (fn WidgetFunc) UIs(c *Context) UIs {
|
func (fn RenderFunc) Uis(c *Context) UI {
|
||||||
return fn(c)
|
return fn(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The type that represents endpoint user interface
|
||||||
|
// via set of components that will work on the same screen
|
||||||
|
// in the same time.
|
||||||
|
type UI []Component
|
||||||
|
|
||||||
// The type describes interfaces
|
// The type describes interfaces
|
||||||
// needed to be implemented to be endpoint handlers.
|
// needed to be implemented to be endpoint handlers.
|
||||||
type UI interface {
|
type Component interface {
|
||||||
Renderable
|
// Optionaly component can implement the
|
||||||
|
// Renderable interface to automaticaly be sent to the
|
||||||
|
// user side.
|
||||||
|
|
||||||
SetMessage(*Message)
|
|
||||||
GetMessage() *Message
|
|
||||||
Filterer
|
Filterer
|
||||||
|
|
||||||
Server
|
Server
|
||||||
}
|
}
|
||||||
|
|
||||||
type UiFunc func()
|
|
||||||
|
|
||||||
// The type to embed into potential components.
|
// The type to embed into potential components.
|
||||||
// Implements empty versions of interfaces
|
// Implements empty versions of interfaces
|
||||||
// and contains
|
// and contains
|
||||||
|
|
|
@ -7,7 +7,8 @@ import (
|
||||||
//"path"
|
//"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
// General type function for faster typing.
|
// General type function to define actions, single component widgets
|
||||||
|
// and components themselves.
|
||||||
type Func func(*Context)
|
type Func func(*Context)
|
||||||
func (f Func) Act(c *Context) {
|
func (f Func) Act(c *Context) {
|
||||||
f(c)
|
f(c)
|
||||||
|
@ -15,16 +16,14 @@ func (f Func) Act(c *Context) {
|
||||||
func (f Func) Serve(c *Context) {
|
func (f Func) Serve(c *Context) {
|
||||||
f(c)
|
f(c)
|
||||||
}
|
}
|
||||||
|
func(f Func) Filter(_ *Context) bool {
|
||||||
// The way to determine where the context is
|
return false
|
||||||
// related to.
|
}
|
||||||
type ContextScope uint8
|
func (f Func) Render(_ *Context) UI {
|
||||||
const (
|
return UI{
|
||||||
NoContextScope ContextScope = iota
|
f,
|
||||||
PrivateContextScope
|
}
|
||||||
GroupContextScope
|
}
|
||||||
ChannelContextScope
|
|
||||||
)
|
|
||||||
|
|
||||||
type ContextType uint8
|
type ContextType uint8
|
||||||
const (
|
const (
|
||||||
|
@ -40,6 +39,8 @@ type context struct {
|
||||||
Session *Session
|
Session *Session
|
||||||
// To reach the bot abilities inside callbacks.
|
// To reach the bot abilities inside callbacks.
|
||||||
Bot *Bot
|
Bot *Bot
|
||||||
|
Type ContextType
|
||||||
|
updates *UpdateChan
|
||||||
skippedUpdates *UpdateChan
|
skippedUpdates *UpdateChan
|
||||||
// Current screen ID.
|
// Current screen ID.
|
||||||
path, prevPath Path
|
path, prevPath Path
|
||||||
|
@ -48,9 +49,7 @@ type context struct {
|
||||||
// Goroutie function to handle each user.
|
// Goroutie function to handle each user.
|
||||||
func (c *Context) serve() {
|
func (c *Context) serve() {
|
||||||
beh := c.Bot.behaviour
|
beh := c.Bot.behaviour
|
||||||
if beh.Init != nil {
|
c.Run(beh.Init)
|
||||||
c.Run(beh.Init, c.Update)
|
|
||||||
}
|
|
||||||
beh.Root.Serve(c)
|
beh.Root.Serve(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +66,7 @@ func (c *Context) PrevPath() Path {
|
||||||
return c.prevPath
|
return c.prevPath
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) Run(a Action, u *Update) {
|
func (c *Context) Run(a Action) {
|
||||||
if a != nil {
|
if a != nil {
|
||||||
a.Act(c.Copy().WithUpdate(u))
|
a.Act(c.Copy().WithUpdate(u))
|
||||||
}
|
}
|
||||||
|
@ -80,12 +79,6 @@ func (c *Context) Skip(u *Update) {
|
||||||
c.skippedUpdates.Send(u)
|
c.skippedUpdates.Send(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renders the Renedrable object to the side of client
|
|
||||||
// and returns the messages it sent.
|
|
||||||
func (c *Context) Render(v Renderable) (MessageMap, error) {
|
|
||||||
return c.Bot.Render(c.Session.Id, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sends to the Sendable object.
|
// Sends to the Sendable object.
|
||||||
func (c *Context) Send(v Sendable) (*Message, error) {
|
func (c *Context) Send(v Sendable) (*Message, error) {
|
||||||
return c.Bot.Send(c.Session.Id, v)
|
return c.Bot.Send(c.Session.Id, v)
|
||||||
|
@ -134,16 +127,19 @@ func (c *Context) Copy() *Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) WithArg(v any) *Context {
|
func (c *Context) WithArg(v any) *Context {
|
||||||
|
c = c.Copy()
|
||||||
c.Arg = v
|
c.Arg = v
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) WithUpdate(u *Update) *Context {
|
func (c *Context) WithUpdate(u *Update) *Context {
|
||||||
|
c = c.Copy()
|
||||||
c.Update = u
|
c.Update = u
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) WithInput(input *UpdateChan) *Context {
|
func (c *Context) WithInput(input *UpdateChan) *Context {
|
||||||
|
c = c.Copy()
|
||||||
c.input = input
|
c.input = input
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -160,9 +156,6 @@ func (af ActionFunc) Act(c *Context) {
|
||||||
af(c)
|
af(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 {
|
||||||
// Getting the screen and changing to
|
// Getting the screen and changing to
|
||||||
|
@ -194,7 +187,7 @@ func (c *Context) PathExist(pth Path) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run widget in background returning the new input channel for it.
|
// Run widget in background returning the new input channel for it.
|
||||||
func (c *Context) runWidget(widget Widget, args ...any) {
|
func (c *Context) runWidget(widget Widget, args ...any) *UpdateChan {
|
||||||
if widget == nil {
|
if widget == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -206,11 +199,19 @@ func (c *Context) runWidget(widget Widget, args ...any) {
|
||||||
arg = args
|
arg = args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pth := c.Path()
|
||||||
uis := widget.UI()
|
uis := widget.UI()
|
||||||
|
// Leave if changed path.
|
||||||
|
if pth != c.Path() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
chns := make(map[UI] *UpdateChan)
|
chns := make(map[UI] *UpdateChan)
|
||||||
for _, ui := range uis {
|
for _, ui := range uis {
|
||||||
msg := c.Send(ui.Render(c))
|
s, ok := ui.(Sendable)
|
||||||
|
if ok {
|
||||||
|
msg := c.Send(s.SendConfig(c))
|
||||||
ui.SetMessage(msg)
|
ui.SetMessage(msg)
|
||||||
|
}
|
||||||
updates := NewUpdateChan()
|
updates := NewUpdateChan()
|
||||||
go func() {
|
go func() {
|
||||||
ui.Serve(
|
ui.Serve(
|
||||||
|
@ -219,19 +220,28 @@ func (c *Context) runWidget(widget Widget, args ...any) {
|
||||||
WithArg(arg),
|
WithArg(arg),
|
||||||
)
|
)
|
||||||
// To let widgets finish themselves before
|
// To let widgets finish themselves before
|
||||||
// the channel is closed.
|
// the channel is closed and close it by themselves.
|
||||||
updates.Close()
|
updates.Close()
|
||||||
}()
|
}()
|
||||||
chns[ui] = updates
|
chns[ui] = updates
|
||||||
}
|
}
|
||||||
|
|
||||||
for u := range c.skippedUpdates.Chan() {
|
ret := NewUpdateChan()
|
||||||
|
go func() {
|
||||||
|
for u := range ret {
|
||||||
for ui := range uis {
|
for ui := range uis {
|
||||||
if !ui.Filter() {
|
if !ui.Filter() {
|
||||||
chns[ui] <- u
|
chns[ui] <- u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ret.Close()
|
||||||
|
for _, chn := range chns {
|
||||||
|
chn.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple way to read strings for widgets.
|
// Simple way to read strings for widgets.
|
||||||
|
|
|
@ -17,6 +17,7 @@ var (
|
||||||
EmptyKeyboardTextErr = errors.New("got empty text for a keyboard")
|
EmptyKeyboardTextErr = errors.New("got empty text for a keyboard")
|
||||||
ActionNotDefinedErr = errors.New("action was not defined")
|
ActionNotDefinedErr = errors.New("action was not defined")
|
||||||
MapCollisionErr = errors.New("map collision occured")
|
MapCollisionErr = errors.New("map collision occured")
|
||||||
|
ContextNotExistErr = errors.New("the context does not exist")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (wut WrongUpdateType) Error() string {
|
func (wut WrongUpdateType) Error() string {
|
||||||
|
|
21
tg/inline.go
21
tg/inline.go
|
@ -9,14 +9,6 @@ type Inline struct {
|
||||||
*Keyboard
|
*Keyboard
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform the keyboard to widget with the specified text.
|
|
||||||
func (kbd *Inline) Widget(text string) *InlineWidget {
|
|
||||||
ret := &InlineWidget{}
|
|
||||||
ret.Inline = kbd
|
|
||||||
ret.Text = text
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the inline keyboard to markup for the tgbotapi.
|
// Convert the inline keyboard to markup for the tgbotapi.
|
||||||
func (kbd *Inline) ToApi() tgbotapi.InlineKeyboardMarkup {
|
func (kbd *Inline) ToApi() tgbotapi.InlineKeyboardMarkup {
|
||||||
rows := [][]tgbotapi.InlineKeyboardButton{}
|
rows := [][]tgbotapi.InlineKeyboardButton{}
|
||||||
|
@ -31,6 +23,14 @@ func (kbd *Inline) ToApi() tgbotapi.InlineKeyboardMarkup {
|
||||||
return tgbotapi.NewInlineKeyboardMarkup(rows...)
|
return tgbotapi.NewInlineKeyboardMarkup(rows...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform the keyboard to widget with the specified text.
|
||||||
|
func (kbd *Inline) Compo(text string) *InlineCompo {
|
||||||
|
ret := &InlinCompo{}
|
||||||
|
ret.Inline = kbd
|
||||||
|
ret.Text = text
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
// The type implements message with an inline keyboard.
|
// The type implements message with an inline keyboard.
|
||||||
type InlineCompo struct {
|
type InlineCompo struct {
|
||||||
Compo
|
Compo
|
||||||
|
@ -39,7 +39,7 @@ type InlineCompo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementing the Sendable interface.
|
// Implementing the Sendable interface.
|
||||||
func (widget *InlineWidget) SendConfig(
|
func (widget *InlineCompo) SendConfig(
|
||||||
c *Context,
|
c *Context,
|
||||||
) (*SendConfig) {
|
) (*SendConfig) {
|
||||||
var text string
|
var text string
|
||||||
|
@ -58,7 +58,7 @@ func (widget *InlineWidget) SendConfig(
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementing the Widget interface.
|
// Implementing the Server interface.
|
||||||
func (widget *InlineCompo) Serve(c *Context) {
|
func (widget *InlineCompo) Serve(c *Context) {
|
||||||
for u := range c.Input() {
|
for u := range c.Input() {
|
||||||
var act Action
|
var act Action
|
||||||
|
@ -91,6 +91,7 @@ func (widget *InlineCompo) Serve(c *Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implementing the Filterer interface.
|
||||||
func (compo *InlineCompo) Filter(u *Update) bool {
|
func (compo *InlineCompo) Filter(u *Update) bool {
|
||||||
if widget == nil || u.CallbackQuery == nil {
|
if widget == nil || u.CallbackQuery == nil {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -51,8 +51,8 @@ func (kbd *Reply) ToApi() any {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform the keyboard to widget with the specified text.
|
// Transform the keyboard to widget with the specified text.
|
||||||
func (kbd *Reply) Widget(text string) *ReplyWidget {
|
func (kbd *Reply) Compo(text string) *ReplyCompo {
|
||||||
ret := &ReplyWidget{}
|
ret := &ReplyCompo{}
|
||||||
ret.Reply = kbd
|
ret.Reply = kbd
|
||||||
ret.Text = text
|
ret.Text = text
|
||||||
return ret
|
return ret
|
||||||
|
@ -112,7 +112,7 @@ func (compo *ReplyCompo) Filter(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementing the Widget interface.
|
// Implementing the UI interface.
|
||||||
func (compo *ReplyCompo) Serve(c *Context) {
|
func (compo *ReplyCompo) Serve(c *Context) {
|
||||||
for u := range c.Input() {
|
for u := range c.Input() {
|
||||||
var btn *Button
|
var btn *Button
|
||||||
|
|
|
@ -9,8 +9,10 @@ type MessageId int64
|
||||||
// Implementing the interface provides
|
// Implementing the interface provides
|
||||||
// way to define what message will be
|
// way to define what message will be
|
||||||
// sent to the side of a user.
|
// sent to the side of a user.
|
||||||
type Renderable interface {
|
type Sendable interface {
|
||||||
Render(*Context) (*SendConfig)
|
SendConfig(*Context) (*SendConfig)
|
||||||
|
SetMessage(*Message)
|
||||||
|
GetMessage() *Message
|
||||||
}
|
}
|
||||||
|
|
||||||
type Errorer interface {
|
type Errorer interface {
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
package tg
|
package tg
|
||||||
|
|
||||||
|
// The way to determine where the context is
|
||||||
|
// related to.
|
||||||
|
type SessionScope uint8
|
||||||
|
const (
|
||||||
|
NoSessionScope ContextScope = iota
|
||||||
|
PrivateSessionScope
|
||||||
|
GroupSessionScope
|
||||||
|
ChannelSessionScope
|
||||||
|
)
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -14,6 +24,7 @@ func (si SessionId) ToApi() int64 {
|
||||||
type Session struct {
|
type Session struct {
|
||||||
// Id of the chat of the user.
|
// Id of the chat of the user.
|
||||||
Id SessionId
|
Id SessionId
|
||||||
|
Scope SessionScope
|
||||||
// Custom value for each user.
|
// Custom value for each user.
|
||||||
Data any
|
Data any
|
||||||
}
|
}
|
||||||
|
@ -30,8 +41,10 @@ func NewSession(id SessionId) *Session {
|
||||||
type SessionMap map[SessionId]*Session
|
type SessionMap map[SessionId]*Session
|
||||||
|
|
||||||
// Add new empty session by it's ID.
|
// Add new empty session by it's ID.
|
||||||
func (sm SessionMap) Add(sid SessionId) {
|
func (sm SessionMap) Add(sid SessionId) *Session {
|
||||||
|
ret := NewSession(sid)
|
||||||
sm[sid] = NewSession(sid)
|
sm[sid] = NewSession(sid)
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session information for a group.
|
// Session information for a group.
|
||||||
|
|
|
@ -4,7 +4,4 @@ type Maker[V any] interface {
|
||||||
Make(*Context) V
|
Make(*Context) V
|
||||||
}
|
}
|
||||||
|
|
||||||
type RootHandler interface {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue