messages_text.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package ui
  2. import (
  3. "log"
  4. "github.com/ayn2op/discordo/discordmd"
  5. "github.com/diamondburned/arikawa/v3/discord"
  6. "github.com/gdamore/tcell/v2"
  7. "github.com/rivo/tview"
  8. )
  9. type MessagesText struct {
  10. *tview.TextView
  11. // The index of the currently selected message. A negative index indicates that there is no currently selected message.
  12. selected int
  13. app *Application
  14. }
  15. func newMessagesText(app *Application) *MessagesText {
  16. mt := &MessagesText{
  17. TextView: tview.NewTextView(),
  18. selected: -1,
  19. app: app,
  20. }
  21. mt.SetDynamicColors(true)
  22. mt.SetRegions(true)
  23. mt.SetWordWrap(true)
  24. mt.SetInputCapture(mt.onInputCapture)
  25. mt.SetChangedFunc(func() {
  26. mt.app.Draw()
  27. })
  28. mt.SetTitle("Messages")
  29. mt.SetTitleAlign(tview.AlignLeft)
  30. mt.SetBorder(true)
  31. mt.SetBorderPadding(0, 0, 1, 1)
  32. return mt
  33. }
  34. func (v *MessagesText) setTitle(c *discord.Channel) {
  35. title := channelToString(*c)
  36. if c.Topic != "" {
  37. title += " - " + discordmd.Parse(c.Topic)
  38. }
  39. v.SetTitle(title)
  40. }
  41. func (v *MessagesText) loadMessages(c *discord.Channel) {
  42. // The returned slice will be sorted from latest to oldest.
  43. ms, err := v.app.state.Messages(c.ID, v.app.config.MessagesLimit)
  44. if err != nil {
  45. log.Println(err)
  46. return
  47. }
  48. for i := len(ms) - 1; i >= 0; i-- {
  49. _, err = v.app.view.MessagesText.Write(buildMessage(v.app, ms[i]))
  50. if err != nil {
  51. log.Println(err)
  52. continue
  53. }
  54. }
  55. v.ScrollToEnd()
  56. }
  57. func (v *MessagesText) onInputCapture(e *tcell.EventKey) *tcell.EventKey {
  58. if v.app.view.ChannelsTree.selected == nil {
  59. return nil
  60. }
  61. // Messages should return messages ordered from latest to earliest.
  62. ms, err := v.app.state.Cabinet.Messages(v.app.view.ChannelsTree.selected.ID)
  63. if err != nil || len(ms) == 0 {
  64. return nil
  65. }
  66. switch e.Name() {
  67. case v.app.config.Keys.MessagesText.LaunchActions:
  68. return v.openActionsView(ms)
  69. case v.app.config.Keys.MessagesText.SelectPrevious:
  70. return v.selectPreviousMessage(ms)
  71. case v.app.config.Keys.MessagesText.SelectNext:
  72. return v.selectNextMessage(ms)
  73. case v.app.config.Keys.MessagesText.SelectFirst:
  74. return v.selectFirstMessage(ms)
  75. case v.app.config.Keys.MessagesText.SelectLast:
  76. return v.selectLastMessage(ms)
  77. case "Esc":
  78. v.selected = -1
  79. v.app.view.ChannelsTree.selected = nil
  80. v.app.SetFocus(v.app.view)
  81. v.
  82. Clear().
  83. Highlight().
  84. SetTitle("")
  85. return nil
  86. }
  87. return e
  88. }
  89. func (v *MessagesText) selectPreviousMessage(ms []discord.Message) *tcell.EventKey {
  90. // If there are no highlighted regions, select the latest (last) message.
  91. if len(v.GetHighlights()) == 0 {
  92. v.selected = 0
  93. } else {
  94. // If the selected message is the oldest (first) message, select the latest (last) message.
  95. if v.selected == len(ms)-1 {
  96. v.selected = 0
  97. } else {
  98. v.selected++
  99. }
  100. }
  101. v.Highlight(ms[v.selected].ID.String())
  102. v.ScrollToHighlight()
  103. return nil
  104. }
  105. func (v *MessagesText) selectNextMessage(ms []discord.Message) *tcell.EventKey {
  106. // If there are no highlighted regions, select the latest (last) message.
  107. if len(v.GetHighlights()) == 0 {
  108. v.selected = 0
  109. } else {
  110. // If the selected message is the latest (last) message, select the oldest (first) message.
  111. if v.selected == 0 {
  112. v.selected = len(ms) - 1
  113. } else {
  114. v.selected--
  115. }
  116. }
  117. v.
  118. Highlight(ms[v.selected].ID.String()).
  119. ScrollToHighlight()
  120. return nil
  121. }
  122. func (v *MessagesText) selectFirstMessage(ms []discord.Message) *tcell.EventKey {
  123. v.selected = len(ms) - 1
  124. v.
  125. Highlight(ms[v.selected].ID.String()).
  126. ScrollToHighlight()
  127. return nil
  128. }
  129. func (v *MessagesText) selectLastMessage(ms []discord.Message) *tcell.EventKey {
  130. v.selected = 0
  131. v.
  132. Highlight(ms[v.selected].ID.String()).
  133. ScrollToHighlight()
  134. return nil
  135. }
  136. func (v *MessagesText) openActionsView(ms []discord.Message) *tcell.EventKey {
  137. hs := v.GetHighlights()
  138. if len(hs) == 0 {
  139. return nil
  140. }
  141. mID, err := discord.ParseSnowflake(hs[0])
  142. if err != nil {
  143. return nil
  144. }
  145. _, m := findMessageByID(ms, discord.MessageID(mID))
  146. if m == nil {
  147. return nil
  148. }
  149. actionsView := newActionsList(v.app, m)
  150. v.app.SetRoot(actionsView, true)
  151. return nil
  152. }