diff --git a/internal/ui/chat/events.go b/internal/ui/chat/events.go index 35ffbca..95440ef 100644 --- a/internal/ui/chat/events.go +++ b/internal/ui/chat/events.go @@ -9,3 +9,11 @@ func NewLogoutEvent() *LogoutEvent { event.SetEventNow() return event } + +type QuitEvent struct{ tcell.EventTime } + +func NewQuitEvent() *QuitEvent { + event := &QuitEvent{} + event.SetEventNow() + return event +} diff --git a/internal/ui/chat/view.go b/internal/ui/chat/view.go index 62b9bb0..1cdf168 100644 --- a/internal/ui/chat/view.go +++ b/internal/ui/chat/view.go @@ -50,9 +50,10 @@ type View struct { app *tview.Application cfg *config.Config state *ningen.State + token string } -func NewView(app *tview.Application, cfg *config.Config) *View { +func NewView(app *tview.Application, cfg *config.Config, token string) *View { v := &View{ Layers: layers.New(), @@ -62,8 +63,9 @@ func NewView(app *tview.Application, cfg *config.Config) *View { typers: make(map[discord.UserID]*time.Timer), - app: app, - cfg: cfg, + app: app, + cfg: cfg, + token: token, } v.guildsTree = newGuildsTree(cfg, v) @@ -220,6 +222,19 @@ func (v *View) focusNext() { func (v *View) HandleEvent(event tcell.Event) tview.Command { switch event := event.(type) { + case *tview.InitEvent: + return tview.EventCommand(func() tcell.Event { + if err := v.OpenState(v.token); err != nil { + slog.Error("failed to open chat state", "err", err) + return tcell.NewEventError(err) + } + return nil + }) + case *QuitEvent: + if err := v.CloseState(); err != nil { + slog.Error("failed to close the session", "err", err) + } + return tview.QuitCommand{} case *tview.KeyEvent: redraw := tview.RedrawCommand{} switch { diff --git a/internal/ui/login/events.go b/internal/ui/login/events.go new file mode 100644 index 0000000..8fa4acf --- /dev/null +++ b/internal/ui/login/events.go @@ -0,0 +1,14 @@ +package login + +import "github.com/gdamore/tcell/v3" + +type TokenEvent struct { + tcell.EventTime + Token string +} + +func NewTokenEvent(token string) *TokenEvent { + event := &TokenEvent{Token: token} + event.SetEventNow() + return event +} diff --git a/internal/ui/login/form.go b/internal/ui/login/form.go index 27c01ff..064b82c 100644 --- a/internal/ui/login/form.go +++ b/internal/ui/login/form.go @@ -20,23 +20,19 @@ const ( qrLayerName = "qr" ) -type DoneFn = func(token string) - type Form struct { *layers.Layers app *tview.Application cfg *config.Config form *tview.Form - done DoneFn } -func NewForm(app *tview.Application, cfg *config.Config, done DoneFn) *Form { +func NewForm(app *tview.Application, cfg *config.Config) *Form { f := &Form{ Layers: layers.New(), app: app, cfg: cfg, form: tview.NewForm(), - done: done, } f.form. @@ -56,10 +52,7 @@ func (f *Form) login() { } go keyring.SetToken(token) - - if f.done != nil { - f.done(token) - } + f.app.QueueEvent(NewTokenEvent(token)) } func (f *Form) onError(err error) { @@ -118,9 +111,7 @@ func (f *Form) loginWithQR() { go keyring.SetToken(token) f.RemoveLayer(qrLayerName) - if f.done != nil { - f.done(token) - } + f.app.QueueEvent(NewTokenEvent(token)) }) f.AddLayer(qr, layers.WithName(qrLayerName), layers.WithResize(true), layers.WithVisible(true)) diff --git a/internal/ui/root/view.go b/internal/ui/root/view.go index 72aa870..461cb4b 100644 --- a/internal/ui/root/view.go +++ b/internal/ui/root/view.go @@ -1,8 +1,6 @@ package root import ( - "log/slog" - "github.com/ayn2op/discordo/internal/config" "github.com/ayn2op/discordo/internal/consts" "github.com/ayn2op/discordo/internal/ui/chat" @@ -17,9 +15,7 @@ const tokenEnvVarKey = "DISCORDO_TOKEN" type View struct { app *tview.Application inner tview.Primitive - chat *chat.View - - cfg *config.Config + cfg *config.Config } func NewView(cfg *config.Config, app *tview.Application) *View { @@ -29,32 +25,14 @@ func NewView(cfg *config.Config, app *tview.Application) *View { } } -func (v *View) showLoginView() { - loginForm := login.NewForm(v.app, v.cfg, func(token string) { - if err := v.showChatView(token); err != nil { - slog.Error("failed to show chat view", "err", err) - } - }) - v.chat = nil - v.inner = loginForm +func (v *View) showLoginView() tview.Command { + v.inner = login.NewForm(v.app, v.cfg) + return v.inner.HandleEvent(tview.NewInitEvent()) } -func (v *View) showChatView(token string) error { - v.chat = chat.NewView(v.app, v.cfg) - if err := v.chat.OpenState(token); err != nil { - return err - } - v.inner = v.chat - return nil -} - -func (v *View) closeChatViewState() { - if v.chat != nil { - if err := v.chat.CloseState(); err != nil { - slog.Error("failed to close the session", "err", err) - } - v.chat = nil - } +func (v *View) showChatView(token string) tview.Command { + v.inner = chat.NewView(v.app, v.cfg, token) + return v.inner.HandleEvent(tview.NewInitEvent()) } var _ tview.Primitive = (*View)(nil) @@ -75,14 +53,12 @@ func (v *View) HandleEvent(event tcell.Event) tview.Command { } case *tokenEvent: if event.token == "" { - v.showLoginView() + return tview.BatchCommand{v.showLoginView(), tview.SetFocusCommand{Target: v.inner}} } else { - if err := v.showChatView(event.token); err != nil { - slog.Error("failed to show chat view", "err", err) - return tview.QuitCommand{} - } + return tview.BatchCommand{v.showChatView(event.token), tview.SetFocusCommand{Target: v.inner}} } - return tview.BatchCommand{tview.SetFocusCommand{Target: v.inner}} + case *login.TokenEvent: + return tview.BatchCommand{v.showChatView(event.Token), tview.SetFocusCommand{Target: v.inner}} case *chat.LogoutEvent: v.showLoginView() return tview.BatchCommand{ @@ -96,7 +72,9 @@ func (v *View) HandleEvent(event tcell.Event) tview.Command { v.suspend() return nil case keybind.Matches(event, v.cfg.Keybinds.Quit.Keybind): - v.closeChatViewState() + if v.inner != nil { + return v.inner.HandleEvent(chat.NewQuitEvent()) + } return tview.QuitCommand{} } }