view.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package root
  2. import (
  3. "log/slog"
  4. "os"
  5. "github.com/ayn2op/discordo/internal/clipboard"
  6. "github.com/ayn2op/discordo/internal/config"
  7. "github.com/ayn2op/discordo/internal/keyring"
  8. "github.com/ayn2op/discordo/internal/ui/chat"
  9. "github.com/ayn2op/discordo/internal/ui/login"
  10. "github.com/ayn2op/tview"
  11. "github.com/ayn2op/tview/keybind"
  12. "github.com/gdamore/tcell/v3"
  13. )
  14. const tokenEnvVarKey = "DISCORDO_TOKEN"
  15. type View struct {
  16. *tview.Box
  17. app *tview.Application
  18. inner tview.Primitive
  19. chat *chat.View
  20. cfg *config.Config
  21. }
  22. func NewView(cfg *config.Config, app *tview.Application) *View {
  23. tview.Styles = tview.Theme{}
  24. v := &View{
  25. app: app,
  26. Box: tview.NewBox(),
  27. cfg: cfg,
  28. }
  29. if err := clipboard.Init(); err != nil {
  30. slog.Error("failed to init clipboard", "err", err)
  31. }
  32. return v
  33. }
  34. func (v *View) showLoginView() {
  35. loginForm := login.NewForm(v.app, v.cfg, func(token string) {
  36. if err := v.showChatView(token); err != nil {
  37. slog.Error("failed to show chat view", "err", err)
  38. }
  39. })
  40. v.inner = loginForm
  41. }
  42. func (v *View) showChatView(token string) error {
  43. v.chat = chat.NewView(v.app, v.cfg, v.showLoginView)
  44. if err := v.chat.OpenState(token); err != nil {
  45. return err
  46. }
  47. v.inner = v.chat
  48. return nil
  49. }
  50. func (v *View) closeChatViewState() {
  51. if v.chat != nil {
  52. if err := v.chat.CloseState(); err != nil {
  53. slog.Error("failed to close the session", "err", err)
  54. }
  55. v.chat = nil
  56. }
  57. }
  58. func (v *View) Draw(screen tcell.Screen) {
  59. if v.inner == nil {
  60. return
  61. }
  62. x, y, width, height := v.GetRect()
  63. v.inner.SetRect(x, y, width, height)
  64. v.inner.Draw(screen)
  65. }
  66. func (v *View) HandleEvent(event tcell.Event) tview.Command {
  67. switch event := event.(type) {
  68. case *tview.InitEvent:
  69. token := os.Getenv(tokenEnvVarKey)
  70. if token == "" {
  71. tok, err := keyring.GetToken()
  72. if err != nil {
  73. slog.Info("failed to retrieve token from keyring", "err", err)
  74. }
  75. token = tok
  76. }
  77. if token == "" {
  78. v.showLoginView()
  79. } else {
  80. if err := v.showChatView(token); err != nil {
  81. slog.Error("failed to show chat view", "err", err)
  82. return tview.QuitCommand{}
  83. }
  84. }
  85. return tview.SetFocusCommand{Target: v}
  86. case *tview.KeyEvent:
  87. switch {
  88. case keybind.Matches(event, v.cfg.Keybinds.Suspend.Keybind):
  89. v.suspend()
  90. return nil
  91. case keybind.Matches(event, v.cfg.Keybinds.Quit.Keybind):
  92. v.closeChatViewState()
  93. return tview.QuitCommand{}
  94. }
  95. if v.inner != nil {
  96. return v.inner.HandleEvent(event)
  97. }
  98. case *tview.MouseEvent, *tview.PasteEvent:
  99. if v.inner != nil {
  100. return v.inner.HandleEvent(event)
  101. }
  102. }
  103. return nil
  104. }
  105. func (v *View) Focus(delegate func(p tview.Primitive)) {
  106. if v.inner != nil {
  107. delegate(v.inner)
  108. return
  109. }
  110. v.Box.Focus(delegate)
  111. }
  112. func (v *View) HasFocus() bool {
  113. if v.inner != nil && v.inner.HasFocus() {
  114. return true
  115. }
  116. return v.Box.HasFocus()
  117. }
  118. func (v *View) Blur() {
  119. if v.inner != nil {
  120. v.inner.Blur()
  121. }
  122. v.Box.Blur()
  123. }