app.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package ui
  2. import (
  3. "sort"
  4. "strings"
  5. "github.com/ayntgl/astatine"
  6. "github.com/ayntgl/discordo/config"
  7. "github.com/gdamore/tcell/v2"
  8. "github.com/rivo/tview"
  9. )
  10. type App struct {
  11. *tview.Application
  12. MainFlex *tview.Flex
  13. GuildsList *GuildsList
  14. ChannelsTreeView *ChannelsTreeView
  15. MessagesTextView *MessagesTextView
  16. MessageInputField *MessageInputField
  17. Session *astatine.Session
  18. SelectedChannel *astatine.Channel
  19. Config *config.Config
  20. SelectedMessage int
  21. }
  22. func NewApp(token string, c *config.Config) *App {
  23. app := &App{
  24. MainFlex: tview.NewFlex(),
  25. Session: astatine.New(token),
  26. Config: c,
  27. SelectedMessage: -1,
  28. }
  29. app.GuildsList = NewGuildsList(app)
  30. app.ChannelsTreeView = NewChannelsTreeView(app)
  31. app.MessagesTextView = NewMessagesTextView(app)
  32. app.MessageInputField = NewMessageInputField(app)
  33. app.Application = tview.NewApplication()
  34. app.EnableMouse(app.Config.Mouse)
  35. app.SetInputCapture(app.onInputCapture)
  36. return app
  37. }
  38. func (app *App) Connect() error {
  39. // For user accounts, all of the guilds, the user is in, are dispatched in the READY gateway event.
  40. // Whereas, for bot accounts, the guilds are dispatched discretely in the GUILD_CREATE gateway events.
  41. if !strings.HasPrefix(app.Session.Identify.Token, "Bot") {
  42. app.Session.UserAgent = app.Config.Identify.UserAgent
  43. app.Session.Identify.Compress = false
  44. app.Session.Identify.LargeThreshold = 0
  45. app.Session.Identify.Intents = 0
  46. app.Session.Identify.Properties = astatine.IdentifyProperties{
  47. OS: app.Config.Identify.Os,
  48. Browser: app.Config.Identify.Browser,
  49. }
  50. app.Session.AddHandlerOnce(app.onSessionReady)
  51. }
  52. app.Session.AddHandler(app.onSessionGuildCreate)
  53. app.Session.AddHandler(app.onSessionGuildDelete)
  54. app.Session.AddHandler(app.onSessionMessageCreate)
  55. return app.Session.Open()
  56. }
  57. func (app *App) onInputCapture(e *tcell.EventKey) *tcell.EventKey {
  58. if app.MessageInputField.HasFocus() {
  59. return e
  60. }
  61. if app.MainFlex.GetItemCount() != 0 {
  62. switch e.Name() {
  63. case app.Config.Keys.ToggleGuildsList:
  64. app.SetFocus(app.GuildsList)
  65. return nil
  66. case app.Config.Keys.ToggleChannelsTreeView:
  67. app.SetFocus(app.ChannelsTreeView)
  68. return nil
  69. case app.Config.Keys.ToggleMessagesTextView:
  70. app.SetFocus(app.MessagesTextView)
  71. return nil
  72. case app.Config.Keys.ToggleMessageInputField:
  73. app.SetFocus(app.MessageInputField)
  74. return nil
  75. }
  76. }
  77. return e
  78. }
  79. func (app *App) DrawMainFlex() {
  80. leftFlex := tview.NewFlex().
  81. SetDirection(tview.FlexRow).
  82. AddItem(app.GuildsList, 10, 1, false).
  83. AddItem(app.ChannelsTreeView, 0, 1, false)
  84. rightFlex := tview.NewFlex().
  85. SetDirection(tview.FlexRow).
  86. AddItem(app.MessagesTextView, 0, 1, false).
  87. AddItem(app.MessageInputField, 3, 1, false)
  88. app.MainFlex.
  89. AddItem(leftFlex, 0, 1, false).
  90. AddItem(rightFlex, 0, 4, false)
  91. app.SetRoot(app.MainFlex, true)
  92. }
  93. func (app *App) onSessionReady(_ *astatine.Session, r *astatine.Ready) {
  94. sort.Slice(r.Guilds, func(a, b int) bool {
  95. found := false
  96. for _, guildID := range r.Settings.GuildPositions {
  97. if found && guildID == r.Guilds[b].ID {
  98. return true
  99. }
  100. if !found && guildID == r.Guilds[a].ID {
  101. found = true
  102. }
  103. }
  104. return false
  105. })
  106. for _, g := range r.Guilds {
  107. app.GuildsList.AddItem(g.Name, "", 0, nil)
  108. }
  109. }
  110. func (app *App) onSessionGuildCreate(_ *astatine.Session, g *astatine.GuildCreate) {
  111. app.GuildsList.AddItem(g.Name, "", 0, nil)
  112. app.Draw()
  113. }
  114. func (app *App) onSessionGuildDelete(_ *astatine.Session, g *astatine.GuildDelete) {
  115. items := app.GuildsList.FindItems(g.BeforeDelete.Name, "", false, false)
  116. if len(items) != 0 {
  117. app.GuildsList.RemoveItem(items[0])
  118. }
  119. app.Draw()
  120. }
  121. func (app *App) onSessionMessageCreate(_ *astatine.Session, m *astatine.MessageCreate) {
  122. if app.SelectedChannel != nil && app.SelectedChannel.ID == m.ChannelID {
  123. app.SelectedChannel.Messages = append(app.SelectedChannel.Messages, m.Message)
  124. _, err := app.MessagesTextView.Write(buildMessage(app, m.Message))
  125. if err != nil {
  126. return
  127. }
  128. if len(app.MessagesTextView.GetHighlights()) == 0 {
  129. app.MessagesTextView.ScrollToEnd()
  130. }
  131. }
  132. }