view.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package root
  2. import (
  3. "github.com/ayn2op/discordo/internal/config"
  4. "github.com/ayn2op/discordo/internal/consts"
  5. "github.com/ayn2op/discordo/internal/ui/chat"
  6. "github.com/ayn2op/discordo/internal/ui/login"
  7. "github.com/ayn2op/tview"
  8. "github.com/ayn2op/tview/help"
  9. "github.com/ayn2op/tview/keybind"
  10. "github.com/gdamore/tcell/v3"
  11. )
  12. const tokenEnvVarKey = "DISCORDO_TOKEN"
  13. type View struct {
  14. app *tview.Application
  15. rootFlex *tview.Flex // inner + help
  16. inner tview.Primitive
  17. help *help.Help
  18. cfg *config.Config
  19. }
  20. func NewView(cfg *config.Config, app *tview.Application) *View {
  21. v := &View{
  22. app: app,
  23. rootFlex: tview.NewFlex(),
  24. help: help.New(),
  25. cfg: cfg,
  26. }
  27. v.rootFlex.SetDirection(tview.FlexRow)
  28. styles := help.DefaultStyles()
  29. styles.ShortKeyStyle = cfg.Theme.Help.ShortKeyStyle.Style
  30. styles.ShortDescStyle = cfg.Theme.Help.ShortDescStyle.Style
  31. styles.FullKeyStyle = cfg.Theme.Help.FullKeyStyle.Style
  32. styles.FullDescStyle = cfg.Theme.Help.FullDescStyle.Style
  33. v.help.SetStyles(styles)
  34. v.help.SetKeyMap(v)
  35. v.help.SetCompactModifiers(cfg.Help.CompactModifiers)
  36. v.help.SetShortSeparator(cfg.Help.Separator)
  37. v.help.SetBorderPadding(0, 0, cfg.Help.Padding[0], cfg.Help.Padding[1])
  38. v.buildLayout()
  39. return v
  40. }
  41. func (v *View) showLoginView() tview.Command {
  42. v.inner = login.NewForm(v.app, v.cfg)
  43. v.buildLayout()
  44. return v.inner.HandleEvent(tview.NewInitEvent())
  45. }
  46. func (v *View) showChatView(token string) tview.Command {
  47. v.inner = chat.NewView(v.app, v.cfg, token)
  48. v.buildLayout()
  49. return v.inner.HandleEvent(tview.NewInitEvent())
  50. }
  51. func (v *View) buildLayout() {
  52. v.rootFlex.Clear()
  53. content := v.inner
  54. if content == nil {
  55. content = tview.NewBox()
  56. }
  57. v.rootFlex.AddItem(content, 0, 1, true)
  58. v.rootFlex.AddItem(v.help, 1, 0, false)
  59. v.updateHelpHeight()
  60. }
  61. var _ tview.Primitive = (*View)(nil)
  62. func (v *View) Draw(screen tcell.Screen) {
  63. v.rootFlex.Draw(screen)
  64. }
  65. func (v *View) HandleEvent(event tcell.Event) tview.Command {
  66. switch event := event.(type) {
  67. case *tview.InitEvent:
  68. return tview.BatchCommand{
  69. tview.SetTitleCommand(consts.Name),
  70. tview.EventCommand(initClipboard),
  71. tview.EventCommand(getToken),
  72. }
  73. case *tokenEvent:
  74. if event.token == "" {
  75. return tview.BatchCommand{v.showLoginView(), tview.SetFocusCommand{Target: v.inner}}
  76. } else {
  77. return tview.BatchCommand{v.showChatView(event.token), tview.SetFocusCommand{Target: v.inner}}
  78. }
  79. case *login.TokenEvent:
  80. return tview.BatchCommand{v.showChatView(event.Token), tview.SetFocusCommand{Target: v.inner}}
  81. case *chat.LogoutEvent:
  82. v.showLoginView()
  83. return tview.BatchCommand{
  84. tview.EventCommand(deleteToken),
  85. tview.SetFocusCommand{Target: v.inner},
  86. }
  87. case *tview.KeyEvent:
  88. switch {
  89. case keybind.Matches(event, v.cfg.Keybinds.ToggleHelp.Keybind):
  90. v.help.SetShowAll(!v.help.ShowAll())
  91. v.updateHelpHeight()
  92. return tview.RedrawCommand{}
  93. case keybind.Matches(event, v.cfg.Keybinds.Suspend.Keybind):
  94. v.suspend()
  95. return nil
  96. case keybind.Matches(event, v.cfg.Keybinds.Quit.Keybind):
  97. var innerCmd tview.Command
  98. if v.inner != nil {
  99. innerCmd = v.inner.HandleEvent(chat.NewQuitEvent())
  100. }
  101. return tview.BatchCommand{innerCmd, tview.QuitCommand{}}
  102. }
  103. }
  104. if v.inner != nil {
  105. return v.inner.HandleEvent(event)
  106. }
  107. return nil
  108. }
  109. func (v *View) updateHelpHeight() {
  110. height := 1
  111. if v.help.ShowAll() {
  112. height = max(len(v.help.FullHelpLines(v.FullHelp(), 0)), 1)
  113. }
  114. v.rootFlex.ResizeItem(v.help, height, 0)
  115. }
  116. func (v *View) GetRect() (int, int, int, int) {
  117. return v.rootFlex.GetRect()
  118. }
  119. func (v *View) SetRect(x int, y int, width int, height int) {
  120. v.rootFlex.SetRect(x, y, width, height)
  121. }
  122. func (v *View) Focus(delegate func(p tview.Primitive)) {
  123. if v.inner != nil {
  124. delegate(v.inner)
  125. }
  126. }
  127. func (v *View) HasFocus() bool {
  128. if v.inner != nil {
  129. return v.inner.HasFocus()
  130. }
  131. return true
  132. }
  133. func (v *View) Blur() {
  134. if v.inner != nil {
  135. v.inner.Blur()
  136. }
  137. }