message_actions_list.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package ui
  2. import (
  3. "io"
  4. "net/http"
  5. "os"
  6. "path/filepath"
  7. "regexp"
  8. "github.com/atotto/clipboard"
  9. "github.com/diamondburned/arikawa/v3/discord"
  10. "github.com/rivo/tview"
  11. "github.com/skratchdot/open-golang/open"
  12. )
  13. var linkRegex = regexp.MustCompile("https?://.+")
  14. type MessageActionsList struct {
  15. *tview.List
  16. core *Core
  17. message *discord.Message
  18. }
  19. func NewMessageActionsList(c *Core, m *discord.Message) *MessageActionsList {
  20. mal := &MessageActionsList{
  21. List: tview.NewList(),
  22. core: c,
  23. message: m,
  24. }
  25. mal.ShowSecondaryText(false)
  26. mal.SetDoneFunc(func() {
  27. c.Application.SetRoot(c.MainFlex, true)
  28. c.Application.SetFocus(c.MessagesPanel)
  29. })
  30. // If the client user has the `SEND_MESSAGES` permission, add "Reply" and "Mention Reply" actions.
  31. if hasPermission(c.State, c.ChannelsTree.SelectedChannel.ID, discord.PermissionSendMessages) {
  32. mal.AddItem("Reply", "", 'r', mal.replyAction)
  33. mal.AddItem("Mention Reply", "", 'R', mal.mentionReplyAction)
  34. }
  35. // If the referenced message exists, add a new action to select the reply.
  36. if m.ReferencedMessage != nil {
  37. mal.AddItem("Select Reply", "", 'm', mal.selectReplyAction)
  38. }
  39. // If the content of the message contains link(s), add the appropriate actions to the list.
  40. links := linkRegex.FindAllString(m.Content, -1)
  41. if len(links) != 0 {
  42. mal.AddItem("Open Link", "", 'l', func() {
  43. for _, l := range links {
  44. go open.Run(l)
  45. }
  46. c.Application.SetRoot(c.MainFlex, true)
  47. c.Application.SetFocus(c.MessagesPanel)
  48. })
  49. }
  50. // If the message contains attachments, add the appropriate actions to the actions list.
  51. if len(m.Attachments) != 0 {
  52. mal.AddItem("Open Attachment", "", 'o', mal.openAttachmentAction)
  53. mal.AddItem("Download Attachment", "", 'd', mal.downloadAttachmentAction)
  54. }
  55. // If the client user has the `MANAGE_MESSAGES` permission, add a new action to delete the message.
  56. if hasPermission(c.State, c.ChannelsTree.SelectedChannel.ID, discord.PermissionManageMessages) {
  57. mal.AddItem("Delete", "", 'd', mal.deleteAction)
  58. }
  59. mal.AddItem("Copy Content", "", 'c', mal.copyContentAction)
  60. mal.AddItem("Copy ID", "", 'i', mal.copyIDAction)
  61. mal.SetTitle("Press the Escape key to close")
  62. mal.SetTitleAlign(tview.AlignLeft)
  63. mal.SetBorder(true)
  64. mal.SetBorderPadding(0, 0, 1, 1)
  65. return mal
  66. }
  67. func (mal *MessageActionsList) replyAction() {
  68. mal.core.MessageInput.SetTitle("Replying to " + mal.message.Author.Tag())
  69. mal.core.Application.SetRoot(mal.core.MainFlex, true)
  70. mal.core.Application.SetFocus(mal.core.MessageInput)
  71. }
  72. func (mal *MessageActionsList) mentionReplyAction() {
  73. mal.core.MessageInput.SetTitle("[@] Replying to " + mal.message.Author.Tag())
  74. mal.core.Application.SetRoot(mal.core.MainFlex, true)
  75. mal.core.Application.SetFocus(mal.core.MessageInput)
  76. }
  77. func (mal *MessageActionsList) selectReplyAction() {
  78. ms, err := mal.core.State.Cabinet.Messages(mal.message.ChannelID)
  79. if err != nil {
  80. return
  81. }
  82. mal.core.MessagesPanel.SelectedMessage, _ = findMessageByID(ms, mal.message.ReferencedMessage.ID)
  83. mal.core.MessagesPanel.
  84. Highlight(mal.message.ReferencedMessage.ID.String()).
  85. ScrollToHighlight()
  86. mal.core.Application.SetRoot(mal.core.MainFlex, true)
  87. mal.core.Application.SetFocus(mal.core.MessagesPanel)
  88. }
  89. func (mal *MessageActionsList) openAttachmentAction() {
  90. for _, a := range mal.message.Attachments {
  91. cacheDirPath, _ := os.UserCacheDir()
  92. f, err := os.Create(filepath.Join(cacheDirPath, a.Filename))
  93. if err != nil {
  94. return
  95. }
  96. defer f.Close()
  97. resp, err := http.Get(a.URL)
  98. if err != nil {
  99. return
  100. }
  101. d, err := io.ReadAll(resp.Body)
  102. if err != nil {
  103. return
  104. }
  105. f.Write(d)
  106. go open.Run(f.Name())
  107. }
  108. mal.core.Application.SetRoot(mal.core.MainFlex, true)
  109. mal.core.Application.SetFocus(mal.core.MessagesPanel)
  110. }
  111. func (mal *MessageActionsList) downloadAttachmentAction() {
  112. for _, a := range mal.message.Attachments {
  113. path, err := os.UserHomeDir()
  114. if err != nil {
  115. path = os.TempDir()
  116. }
  117. path = filepath.Join(path, "Downloads", a.Filename)
  118. f, err := os.Create(path)
  119. if err != nil {
  120. return
  121. }
  122. defer f.Close()
  123. resp, err := http.Get(a.URL)
  124. if err != nil {
  125. return
  126. }
  127. d, err := io.ReadAll(resp.Body)
  128. if err != nil {
  129. return
  130. }
  131. f.Write(d)
  132. }
  133. mal.core.Application.SetRoot(mal.core.MainFlex, true)
  134. mal.core.Application.SetFocus(mal.core.MessagesPanel)
  135. }
  136. func (mal *MessageActionsList) deleteAction() {
  137. mal.core.MessagesPanel.Clear()
  138. err := mal.core.State.MessageRemove(mal.message.ChannelID, mal.message.ID)
  139. if err != nil {
  140. return
  141. }
  142. err = mal.core.State.DeleteMessage(mal.message.ChannelID, mal.message.ID, "Unknown")
  143. if err != nil {
  144. return
  145. }
  146. // The returned slice will be sorted from latest to oldest.
  147. ms, err := mal.core.State.Cabinet.Messages(mal.message.ChannelID)
  148. if err != nil {
  149. return
  150. }
  151. for i := len(ms) - 1; i >= 0; i-- {
  152. _, err = mal.core.MessagesPanel.Write(buildMessage(mal.core, ms[i]))
  153. if err != nil {
  154. return
  155. }
  156. }
  157. mal.core.Application.SetRoot(mal.core.MainFlex, true)
  158. mal.core.Application.SetFocus(mal.core.MessagesPanel)
  159. }
  160. func (mal *MessageActionsList) copyContentAction() {
  161. err := clipboard.WriteAll(mal.message.Content)
  162. if err != nil {
  163. return
  164. }
  165. mal.core.Application.SetRoot(mal.core.MainFlex, true)
  166. mal.core.Application.SetFocus(mal.core.MessagesPanel)
  167. }
  168. func (mal *MessageActionsList) copyIDAction() {
  169. err := clipboard.WriteAll(mal.message.ID.String())
  170. if err != nil {
  171. return
  172. }
  173. mal.core.Application.SetRoot(mal.core.MainFlex, true)
  174. mal.core.Application.SetFocus(mal.core.MessagesPanel)
  175. }