messages_view.go 3.9 KB

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