application.go 4.6 KB

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