application.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package ui
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "runtime"
  7. "strings"
  8. "github.com/ayntgl/discordo/config"
  9. "github.com/diamondburned/arikawa/v3/api"
  10. "github.com/diamondburned/arikawa/v3/discord"
  11. "github.com/diamondburned/arikawa/v3/gateway"
  12. "github.com/diamondburned/arikawa/v3/state"
  13. "github.com/gdamore/tcell/v2"
  14. "github.com/gen2brain/beeep"
  15. "github.com/rivo/tview"
  16. )
  17. func init() {
  18. tview.Borders.TopLeftFocus = tview.Borders.TopLeft
  19. tview.Borders.TopRightFocus = tview.Borders.TopRight
  20. tview.Borders.BottomLeftFocus = tview.Borders.BottomLeft
  21. tview.Borders.BottomRightFocus = tview.Borders.BottomRight
  22. tview.Borders.HorizontalFocus = tview.Borders.Horizontal
  23. tview.Borders.VerticalFocus = tview.Borders.Vertical
  24. tview.Borders.TopLeft = 0
  25. tview.Borders.TopRight = 0
  26. tview.Borders.BottomLeft = 0
  27. tview.Borders.BottomRight = 0
  28. tview.Borders.Horizontal = 0
  29. tview.Borders.Vertical = 0
  30. api.UserAgent = fmt.Sprintf("%s/%s %s/%s", config.Name, "0.1", "arikawa", "v3")
  31. gateway.DefaultIdentity = gateway.IdentifyProperties{
  32. OS: runtime.GOOS,
  33. Browser: config.Name,
  34. Device: "",
  35. }
  36. }
  37. // Application is responsible for initialization and management of the application, widgets, configuration, and state.
  38. type Application struct {
  39. *tview.Application
  40. view *View
  41. config *config.Config
  42. state *state.State
  43. }
  44. func NewApplication(cfg *config.Config) *Application {
  45. app := &Application{
  46. Application: tview.NewApplication(),
  47. config: cfg,
  48. }
  49. app.EnableMouse(app.config.Mouse)
  50. app.SetBeforeDrawFunc(app.onBeforeDraw)
  51. // The styles must be assigned before initializing a new view.
  52. tview.Styles.PrimitiveBackgroundColor = tcell.GetColor(cfg.Theme.Background)
  53. tview.Styles.BorderColor = tcell.GetColor(cfg.Theme.Border)
  54. tview.Styles.TitleColor = tcell.GetColor(cfg.Theme.Title)
  55. app.view = newView(app)
  56. return app
  57. }
  58. func (app *Application) Run(token string) {
  59. if token != "" {
  60. if err := app.Connect(token); err != nil {
  61. log.Fatal(err)
  62. }
  63. app.SetRoot(app.view, true)
  64. app.SetFocus(app.view.GuildsView)
  65. } else {
  66. loginView := newLoginView(app)
  67. app.SetRoot(loginView, true)
  68. }
  69. if err := app.Application.Run(); err != nil {
  70. log.Fatal(err)
  71. }
  72. }
  73. func (app *Application) Connect(token string) error {
  74. app.state = state.New(token)
  75. app.state.AddHandler(app.onReady)
  76. app.state.AddHandler(app.onGuildCreate)
  77. app.state.AddHandler(app.onGuildDelete)
  78. app.state.AddHandler(app.onMessageCreate)
  79. return app.state.Open(context.Background())
  80. }
  81. func (app *Application) onBeforeDraw(screen tcell.Screen) bool {
  82. if app.config.Theme.Background == "default" {
  83. screen.Clear()
  84. }
  85. return false
  86. }
  87. func (c *Application) onReady(r *gateway.ReadyEvent) {
  88. root := c.view.GuildsView.GetRoot()
  89. for _, gf := range r.UserSettings.GuildFolders {
  90. if gf.ID == 0 {
  91. for _, gID := range gf.GuildIDs {
  92. g, err := c.state.Cabinet.Guild(gID)
  93. if err != nil {
  94. log.Println(err)
  95. continue
  96. }
  97. guildNode := tview.NewTreeNode(g.Name)
  98. guildNode.SetReference(g.ID)
  99. root.AddChild(guildNode)
  100. }
  101. } else {
  102. var b strings.Builder
  103. if gf.Color != discord.NullColor {
  104. b.WriteByte('[')
  105. b.WriteString(gf.Color.String())
  106. b.WriteByte(']')
  107. } else {
  108. b.WriteString("[#ED4245]")
  109. }
  110. if gf.Name != "" {
  111. b.WriteString(gf.Name)
  112. } else {
  113. b.WriteString("Folder")
  114. }
  115. b.WriteString("[-]")
  116. folderNode := tview.NewTreeNode(b.String())
  117. root.AddChild(folderNode)
  118. for _, gID := range gf.GuildIDs {
  119. g, err := c.state.Cabinet.Guild(gID)
  120. if err != nil {
  121. log.Println(err)
  122. continue
  123. }
  124. guildNode := tview.NewTreeNode(g.Name)
  125. guildNode.SetReference(g.ID)
  126. folderNode.AddChild(guildNode)
  127. }
  128. }
  129. }
  130. c.view.GuildsView.SetCurrentNode(root)
  131. c.SetFocus(c.view.GuildsView)
  132. }
  133. func (c *Application) onGuildCreate(g *gateway.GuildCreateEvent) {
  134. guildNode := tview.NewTreeNode(g.Name)
  135. guildNode.SetReference(g.ID)
  136. rootNode := c.view.GuildsView.GetRoot()
  137. rootNode.AddChild(guildNode)
  138. c.view.GuildsView.SetCurrentNode(rootNode)
  139. c.SetFocus(c.view.GuildsView)
  140. c.Draw()
  141. }
  142. func (c *Application) onGuildDelete(g *gateway.GuildDeleteEvent) {
  143. rootNode := c.view.GuildsView.GetRoot()
  144. var parentNode *tview.TreeNode
  145. rootNode.Walk(func(node, _ *tview.TreeNode) bool {
  146. if node.GetReference() == g.ID {
  147. parentNode = node
  148. return false
  149. }
  150. return true
  151. })
  152. if parentNode != nil {
  153. rootNode.RemoveChild(parentNode)
  154. }
  155. c.Draw()
  156. }
  157. func (c *Application) onMessageCreate(m *gateway.MessageCreateEvent) {
  158. if c.view.ChannelsView.selected == nil {
  159. if c.config.Notifications {
  160. g, err := c.state.Cabinet.Guild(m.GuildID)
  161. if err != nil {
  162. log.Println(err)
  163. return
  164. }
  165. c, err := c.state.Cabinet.Channel(m.ChannelID)
  166. if err != nil {
  167. log.Println(err)
  168. return
  169. }
  170. go beeep.Notify(fmt.Sprintf("%s %s", g.Name, c.Name), m.Content, "")
  171. }
  172. } else {
  173. _, err := c.view.MessagesView.Write(buildMessage(c, m.Message))
  174. if err != nil {
  175. return
  176. }
  177. if len(c.view.MessagesView.GetHighlights()) == 0 {
  178. c.view.MessagesView.ScrollToEnd()
  179. }
  180. }
  181. }