app.go 2.4 KB

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