layout: simplify markups, add buttons

pull/341/head
Demian 4 years ago
parent 12a486fda8
commit d63ce9ce08

@ -9,23 +9,28 @@ config:
dur: 10m
buttons:
- button: &anchored
unique: anchored
callback_data:
text:
# Shortened reply buttons
help: Help
settings: Settings
# Extended reply button
contact:
text: Send a contact
request_contact: true
# Inline button
stop:
unique: stop
text: Stop
callback_data: '{{.}}'
markups:
reply:
reply_shortened:
- [ help ]
- [ settings ]
reply_extended:
keyboard:
- - text: Send a contact
request_contact: true
- [ contact ]
one_time_keyboard: true
inline:
- - unique: inline
callback_data:
text:
embedded:
- - Help
- - Settings
anchored:
- - *anchored
- [ stop ]

@ -21,18 +21,22 @@ type (
funcs template.FuncMap
config map[string]interface{}
buttons map[string]Button
markups map[string]Markup
locales map[string]*template.Template
}
Markup struct {
tele.ReplyMarkup `yaml:",inline"`
Button = tele.Btn
keyboard *template.Template
inline bool
Markup struct {
inline *bool
keyboard *template.Template
ResizeKeyboard *bool `json:"resize_keyboard,omitempty"` // nil == true
ForceReply bool `json:"force_reply,omitempty"`
OneTimeKeyboard bool `json:"one_time_keyboard,omitempty"`
RemoveKeyboard bool `json:"remove_keyboard,omitempty"`
Selective bool `json:"selective,omitempty"`
}
LocaleFunc func(tele.Recipient) string
)
func New(path string) (*Layout, error) {
@ -125,6 +129,11 @@ func (lt *Layout) text(locale, k string, args ...interface{}) string {
return buf.String()
}
func (lt *Layout) Button(k string) tele.CallbackEndpoint {
btn := lt.buttons[k]
return &btn
}
func (lt *Layout) Markup(c tele.Context, k string, args ...interface{}) *tele.ReplyMarkup {
markup, ok := lt.markups[k]
if !ok {
@ -142,25 +151,24 @@ func (lt *Layout) Markup(c tele.Context, k string, args ...interface{}) *tele.Re
// TODO: Log.
}
r := tele.ReplyMarkup{
ForceReply: markup.ForceReply,
ResizeReplyKeyboard: markup.ResizeReplyKeyboard,
OneTimeKeyboard: markup.OneTimeKeyboard,
ReplyKeyboardRemove: markup.ReplyKeyboardRemove,
Selective: markup.Selective,
}
if markup.inline {
r := &tele.ReplyMarkup{}
if *markup.inline {
if err := yaml.Unmarshal(buf.Bytes(), &r.InlineKeyboard); err != nil {
// TODO: Log.
}
} else {
r.ResizeKeyboard = markup.ResizeKeyboard == nil || *markup.ResizeKeyboard
r.ForceReply = markup.ForceReply
r.OneTimeKeyboard = markup.OneTimeKeyboard
r.RemoveKeyboard = markup.RemoveKeyboard
r.Selective = markup.Selective
if err := yaml.Unmarshal(buf.Bytes(), &r.ReplyKeyboard); err != nil {
// TODO: Log.
}
}
return &r
return r
}
func (lt *Layout) template(tmpl *template.Template, locale string) *template.Template {

@ -28,25 +28,21 @@ func TestLayout(t *testing.T) {
assert.Equal(t, float64(123), lt.Float("num"))
assert.Equal(t, 10*time.Minute, lt.Duration("dur"))
assert.Equal(t, &tele.ReplyMarkup{
ReplyKeyboard: [][]tele.ReplyButton{{{Text: "Send a contact", Contact: true}}},
ResizeReplyKeyboard: true,
OneTimeKeyboard: true,
}, lt.Markup(nil, "reply"))
assert.Equal(t, &tele.ReplyMarkup{
InlineKeyboard: [][]tele.InlineButton{{{Unique: "inline"}}},
}, lt.Markup(nil, "inline"))
assert.Equal(t, &tele.ReplyMarkup{
ReplyKeyboard: [][]tele.ReplyButton{
{{Text: "Help"}},
{{Text: "Settings"}},
},
ResizeReplyKeyboard: true,
}, lt.Markup(nil, "embedded"))
ResizeKeyboard: true,
}, lt.Markup(nil, "reply_shortened"))
assert.Equal(t, &tele.ReplyMarkup{
ReplyKeyboard: [][]tele.ReplyButton{{{Text: "Send a contact", Contact: true}}},
ResizeKeyboard: true,
OneTimeKeyboard: true,
}, lt.Markup(nil, "reply_extended"))
assert.Equal(t, &tele.ReplyMarkup{
InlineKeyboard: [][]tele.InlineButton{{{Unique: "anchored"}}},
}, lt.Markup(nil, "anchored"))
InlineKeyboard: [][]tele.InlineButton{{{Unique: "stop", Text: "Stop", Data: "1"}}},
}, lt.Markup(nil, "inline", 1))
}

@ -4,6 +4,8 @@ import (
tele "gopkg.in/tucnak/telebot.v3"
)
type LocaleFunc func(tele.Recipient) string
func (lt *Layout) Middleware(defaultLocale string, localeFunc ...LocaleFunc) tele.MiddlewareFunc {
var f LocaleFunc
if len(localeFunc) > 0 {

@ -1,6 +1,7 @@
package layout
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
@ -30,6 +31,7 @@ func (lt *Layout) UnmarshalYAML(data []byte) error {
var aux struct {
Settings *Settings
Config map[string]interface{}
Buttons yaml.MapSlice
Markups yaml.MapSlice
Locales map[string]map[string]string
}
@ -58,47 +60,54 @@ func (lt *Layout) UnmarshalYAML(data []byte) error {
}
}
lt.markups = make(map[string]Markup, len(aux.Markups))
for _, item := range aux.Markups {
lt.buttons = make(map[string]Button, len(aux.Buttons))
for _, item := range aux.Buttons {
k, v := item.Key.(string), item.Value
// 1. Shortened reply button
if v, ok := v.(string); ok {
lt.buttons[k] = Button{Text: v}
continue
}
// 2. Extended reply or inline button
data, err := yaml.Marshal(v)
if err != nil {
return err
}
// 1. Normal markup.
var markup struct {
Markup `yaml:",inline"`
Resize *bool `json:"resize_keyboard"`
var btn Button
if err := yaml.Unmarshal(data, &btn); err != nil {
return err
}
if yaml.Unmarshal(data, &markup) == nil {
data, err := yaml.Marshal(markup.ReplyKeyboard)
if err != nil {
return err
}
tmpl, err := template.New(k).Funcs(lt.funcs).Parse(string(data))
if err != nil {
return err
}
lt.buttons[k] = btn
}
markup.Markup.keyboard = tmpl
markup.ResizeReplyKeyboard = markup.Resize == nil || *markup.Resize
lt.markups = make(map[string]Markup, len(aux.Markups))
for _, item := range aux.Markups {
k, v := item.Key.(string), item.Value
lt.markups[k] = markup.Markup
data, err := yaml.Marshal(v)
if err != nil {
return err
}
// 2. Shortened reply markup.
var shortenedMarkup [][]string
if yaml.Unmarshal(data, &shortenedMarkup) == nil {
// 1. Shortened reply or inline markup
var embeddedMarkup [][]string
if yaml.Unmarshal(data, &embeddedMarkup) == nil {
kb := make([][]tele.ReplyButton, len(embeddedMarkup))
for i, btns := range embeddedMarkup {
row := make([]tele.ReplyButton, len(btns))
kb := make([][]Button, len(shortenedMarkup))
for i, btns := range shortenedMarkup {
row := make([]Button, len(btns))
for j, btn := range btns {
row[j] = tele.ReplyButton{Text: btn}
b, ok := lt.buttons[btn]
if !ok {
return fmt.Errorf("telebot/layout: no %s button for %s markup", btn, k)
}
row[j] = b
}
kb[i] = row
}
@ -114,22 +123,51 @@ func (lt *Layout) UnmarshalYAML(data []byte) error {
}
markup := Markup{keyboard: tmpl}
markup.ResizeReplyKeyboard = true
for _, row := range kb {
for _, btn := range row {
inline := btn.Unique != ""
if markup.inline == nil {
markup.inline = &inline
} else if *markup.inline != inline {
return fmt.Errorf("telebot/layout: mixed reply and inline buttons in %s markup", k)
}
}
}
lt.markups[k] = markup
}
} else {
// 2. Extended reply markup
// 3. Shortened inline markup.
var markup struct {
Markup `yaml:",inline"`
Keyboard [][]string `json:"keyboard"`
}
if err := yaml.Unmarshal(data, &markup); err != nil {
return err
}
if yaml.Unmarshal(data, &[][]tele.InlineButton{}) == nil {
tmpl, err := template.New(k).Funcs(lt.funcs).Parse(string(data))
kb := make([][]tele.ReplyButton, len(markup.Keyboard))
for i, btns := range markup.Keyboard {
row := make([]tele.ReplyButton, len(btns))
for j, btn := range btns {
row[j] = *lt.buttons[btn].Reply()
}
kb[i] = row
}
data, err := yaml.Marshal(kb)
if err != nil {
return err
}
lt.markups[k] = Markup{
keyboard: tmpl,
inline: true,
tmpl, err := template.New(k).Funcs(lt.funcs).Parse(string(data))
if err != nil {
return err
}
markup.inline = new(bool)
markup.Markup.keyboard = tmpl
lt.markups[k] = markup.Markup
}
}

Loading…
Cancel
Save