messages_view.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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 MessagesView 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 newMessagesView(app *Application) *MessagesView {
  16. v := &MessagesView{
  17. TextView: tview.NewTextView(),
  18. selected: -1,
  19. app: app,
  20. }
  21. v.SetDynamicColors(true)
  22. v.SetRegions(true)
  23. v.SetWordWrap(true)
  24. v.SetInputCapture(v.onInputCapture)
  25. v.SetChangedFunc(func() {
  26. v.app.Draw()
  27. })
  28. v.SetTitle("Messages")
  29. v.SetTitleAlign(tview.AlignLeft)
  30. v.SetBorder(true)
  31. v.SetBorderPadding(0, 0, 1, 1)
  32. return v
  33. }
  34. func (v *MessagesView) 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 *MessagesView) 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.MessagesView.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 *MessagesView) onInputCapture(e *tcell.EventKey) *tcell.EventKey {
  58. if v.app.view.ChannelsView.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.ChannelsView.selected.ID)
  63. if err != nil || len(ms) == 0 {
  64. return nil
  65. }
  66. switch e.Name() {
  67. case v.app.config.Keys.MessagesView.OpenActionsView:
  68. return v.openActionsView(ms)
  69. case v.app.config.Keys.MessagesView.SelectPreviousMessage:
  70. return v.selectPreviousMessage(ms)
  71. case v.app.config.Keys.MessagesView.SelectNextMessage:
  72. return v.selectNextMessage(ms)
  73. case v.app.config.Keys.MessagesView.SelectFirstMessage:
  74. return v.selectFirstMessage(ms)
  75. case v.app.config.Keys.MessagesView.SelectLastMessage:
  76. return v.selectLastMessage(ms)
  77. case "Esc":
  78. v.selected = -1
  79. v.app.SetFocus(v.app.view)
  80. v.
  81. Clear().
  82. Highlight().
  83. SetTitle("")
  84. return nil
  85. }
  86. return e
  87. }
  88. func (v *MessagesView) selectPreviousMessage(ms []discord.Message) *tcell.EventKey {
  89. // If there are no highlighted regions, select the latest (last) message.
  90. if len(v.GetHighlights()) == 0 {
  91. v.selected = 0
  92. } else {
  93. // If the selected message is the oldest (first) message, select the latest (last) message.
  94. if v.selected == len(ms)-1 {
  95. v.selected = 0
  96. } else {
  97. v.selected++
  98. }
  99. }
  100. v.Highlight(ms[v.selected].ID.String())
  101. v.ScrollToHighlight()
  102. return nil
  103. }
  104. func (v *MessagesView) selectNextMessage(ms []discord.Message) *tcell.EventKey {
  105. // If there are no highlighted regions, select the latest (last) message.
  106. if len(v.GetHighlights()) == 0 {
  107. v.selected = 0
  108. } else {
  109. // If the selected message is the latest (last) message, select the oldest (first) message.
  110. if v.selected == 0 {
  111. v.selected = len(ms) - 1
  112. } else {
  113. v.selected--
  114. }
  115. }
  116. v.
  117. Highlight(ms[v.selected].ID.String()).
  118. ScrollToHighlight()
  119. return nil
  120. }
  121. func (v *MessagesView) selectFirstMessage(ms []discord.Message) *tcell.EventKey {
  122. v.selected = len(ms) - 1
  123. v.
  124. Highlight(ms[v.selected].ID.String()).
  125. ScrollToHighlight()
  126. return nil
  127. }
  128. func (v *MessagesView) selectLastMessage(ms []discord.Message) *tcell.EventKey {
  129. v.selected = 0
  130. v.
  131. Highlight(ms[v.selected].ID.String()).
  132. ScrollToHighlight()
  133. return nil
  134. }
  135. func (v *MessagesView) openActionsView(ms []discord.Message) *tcell.EventKey {
  136. hs := v.GetHighlights()
  137. if len(hs) == 0 {
  138. return nil
  139. }
  140. mID, err := discord.ParseSnowflake(hs[0])
  141. if err != nil {
  142. return nil
  143. }
  144. _, m := findMessageByID(ms, discord.MessageID(mID))
  145. if m == nil {
  146. return nil
  147. }
  148. actionsView := newActionsView(v.app, m)
  149. v.app.SetRoot(actionsView, true)
  150. return nil
  151. }