view.go 3.0 KB

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