app.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package app
  2. import (
  3. "fmt"
  4. "log/slog"
  5. "os"
  6. "github.com/ayn2op/discordo/internal/clipboard"
  7. "github.com/ayn2op/discordo/internal/config"
  8. "github.com/ayn2op/discordo/internal/consts"
  9. "github.com/ayn2op/discordo/internal/keyring"
  10. "github.com/ayn2op/discordo/internal/ui/chat"
  11. "github.com/ayn2op/discordo/internal/ui/login"
  12. "github.com/ayn2op/tview"
  13. "github.com/ayn2op/tview/keybind"
  14. "github.com/gdamore/tcell/v3"
  15. )
  16. type App struct {
  17. inner *tview.Application
  18. chatView *chat.View
  19. cfg *config.Config
  20. }
  21. func New(cfg *config.Config) *App {
  22. tview.Styles = tview.Theme{}
  23. app := &App{
  24. inner: tview.NewApplication(),
  25. cfg: cfg,
  26. }
  27. if err := clipboard.Init(); err != nil {
  28. slog.Error("failed to init clipboard", "err", err)
  29. }
  30. app.inner.SetInputCapture(app.onInputCapture)
  31. return app
  32. }
  33. func (a *App) Run() error {
  34. token := os.Getenv("DISCORDO_TOKEN")
  35. if token == "" {
  36. t, err := keyring.GetToken()
  37. if err != nil {
  38. slog.Info("failed to retrieve token from keyring", "err", err)
  39. }
  40. token = t
  41. }
  42. screen, err := tcell.NewScreen()
  43. if err != nil {
  44. return fmt.Errorf("failed to create screen: %w", err)
  45. }
  46. if err := screen.Init(); err != nil {
  47. return fmt.Errorf("failed to init screen: %w", err)
  48. }
  49. if a.cfg.Mouse {
  50. screen.EnableMouse()
  51. }
  52. screen.SetTitle(consts.Name)
  53. screen.EnablePaste()
  54. screen.EnableFocus()
  55. a.inner.SetScreen(screen)
  56. if token == "" {
  57. loginForm := login.NewForm(a.inner, a.cfg, func(token string) {
  58. if err := a.showChatView(token); err != nil {
  59. slog.Error("failed to show chat view", "err", err)
  60. }
  61. })
  62. a.inner.SetRoot(loginForm)
  63. } else {
  64. if err := a.showChatView(token); err != nil {
  65. return err
  66. }
  67. }
  68. return a.inner.Run()
  69. }
  70. func (a *App) showChatView(token string) error {
  71. a.chatView = chat.NewView(a.inner, a.cfg, a.quit)
  72. if err := a.chatView.OpenState(token); err != nil {
  73. return err
  74. }
  75. a.inner.SetRoot(a.chatView)
  76. return nil
  77. }
  78. func (a *App) quit() {
  79. if a.chatView != nil {
  80. if err := a.chatView.CloseState(); err != nil {
  81. slog.Error("failed to close the session", "err", err)
  82. }
  83. }
  84. a.inner.Stop()
  85. }
  86. func (a *App) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
  87. switch {
  88. case keybind.Matches(event, a.cfg.Keybinds.Suspend.Keybind):
  89. a.suspend()
  90. return nil
  91. case keybind.Matches(event, a.cfg.Keybinds.Quit.Keybind):
  92. a.quit()
  93. return nil
  94. case keybind.Matches(event, keybind.NewKeybind(keybind.WithKeys("ctrl+c"))):
  95. // https://github.com/ayn2op/tview/blob/a64fc48d7654432f71922c8b908280cdb525805c/application.go#L153
  96. return tcell.NewEventKey(tcell.KeyCtrlC, "", tcell.ModNone)
  97. }
  98. return event
  99. }