button.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package tg
  2. import (
  3. apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
  4. "fmt"
  5. "crypto/rand"
  6. "encoding/base64"
  7. )
  8. // The type wraps Telegram API's button to provide Action functionality.
  9. type Button struct {
  10. Text string
  11. Data string
  12. URL string
  13. SendLocation bool
  14. Action Action
  15. // Used to skip buttons in generating by functions.
  16. Valid bool
  17. }
  18. type ButtonMap map[string]Button
  19. // Returns the only location button in the map and if it is there at all.
  20. // The location map must be the ONLY one.
  21. func (btnMap ButtonMap) LocationButton() (Button, bool) {
  22. for _, btn := range btnMap {
  23. if btn.SendLocation {
  24. return btn, true
  25. }
  26. }
  27. return Button{}, false
  28. }
  29. // Represents the reply button row.
  30. type ButtonRow []Button
  31. // Returns new button with the specified text and no action.
  32. func Buttonf(format string, v ...any) Button {
  33. return Button{
  34. Text: fmt.Sprintf(format, v...),
  35. Valid: true,
  36. }
  37. }
  38. // Randomize buttons data to make the key unique.
  39. // No guaranties about collisions though.
  40. func (btn Button) Rand() Button {
  41. rData := make([]byte, 8)
  42. rand.Read(rData)
  43. data := make([]byte, base64.StdEncoding.EncodedLen(len(rData)))
  44. base64.StdEncoding.Encode(data, rData)
  45. btn.Data = string(data)
  46. return btn
  47. }
  48. // Set the URL for the button. Only for inline buttons.
  49. func (btn Button) WithURL(format string, v ...any) Button {
  50. btn.URL = fmt.Sprintf(format, v...)
  51. return btn
  52. }
  53. // Set the action when pressing the button.
  54. // By default is nil and does nothing.
  55. func (btn Button) WithAction(a Action) Button {
  56. btn.Action = a
  57. return btn
  58. }
  59. func (btn Button) WithData(dat string) Button {
  60. btn.Data = dat
  61. return btn
  62. }
  63. // Sets whether the button must send owner's location.
  64. func (btn Button) WithSendLocation(ok bool) Button {
  65. btn.SendLocation = ok
  66. return btn
  67. }
  68. func (btn Button) Go(pth Widget) Button {
  69. return btn.WithAction(WidgetGo{
  70. Path: pth,
  71. })
  72. }
  73. func (btn Button) GoWithArg(pth Widget, arg any) Button {
  74. return btn.WithAction(WidgetGo{
  75. Path: pth,
  76. Arg: arg,
  77. })
  78. }
  79. func (btn Button) ToTelegram() apix.KeyboardButton {
  80. ret := apix.NewKeyboardButton(btn.Text)
  81. if btn.SendLocation {
  82. ret.RequestLocation = true
  83. }
  84. return ret
  85. }
  86. func (btn Button) ToTelegramInline() apix.InlineKeyboardButton {
  87. if btn.Data != "" {
  88. return apix.NewInlineKeyboardButtonData(
  89. btn.Text,
  90. btn.Data,
  91. )
  92. }
  93. if btn.URL != "" {
  94. return apix.NewInlineKeyboardButtonURL(
  95. btn.Text,
  96. btn.URL,
  97. )
  98. }
  99. // If no match then return the data one with data the same as the text.
  100. return apix.NewInlineKeyboardButtonData(btn.Text, btn.Text)
  101. }
  102. // Return the key of the button to identify it by messages and callbacks.
  103. func (btn Button) Key() string {
  104. if btn.Data != "" {
  105. return btn.Data
  106. }
  107. // If no match then return the data one with data the same as the text.
  108. return btn.Text
  109. }
  110. func NewButtonRow(btns ...Button) ButtonRow {
  111. return btns
  112. }