Преглед изворни кода

refactor(ui): route auth and quit through events

ayn2op пре 1 месец
родитељ
комит
5afee6e9fa
5 измењених фајлова са 57 додато и 51 уклоњено
  1. 8 0
      internal/ui/chat/events.go
  2. 18 3
      internal/ui/chat/view.go
  3. 14 0
      internal/ui/login/events.go
  4. 3 12
      internal/ui/login/form.go
  5. 14 36
      internal/ui/root/view.go

+ 8 - 0
internal/ui/chat/events.go

@@ -9,3 +9,11 @@ func NewLogoutEvent() *LogoutEvent {
 	event.SetEventNow()
 	event.SetEventNow()
 	return event
 	return event
 }
 }
+
+type QuitEvent struct{ tcell.EventTime }
+
+func NewQuitEvent() *QuitEvent {
+	event := &QuitEvent{}
+	event.SetEventNow()
+	return event
+}

+ 18 - 3
internal/ui/chat/view.go

@@ -50,9 +50,10 @@ type View struct {
 	app   *tview.Application
 	app   *tview.Application
 	cfg   *config.Config
 	cfg   *config.Config
 	state *ningen.State
 	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{
 	v := &View{
 		Layers: layers.New(),
 		Layers: layers.New(),
 
 
@@ -62,8 +63,9 @@ func NewView(app *tview.Application, cfg *config.Config) *View {
 
 
 		typers: make(map[discord.UserID]*time.Timer),
 		typers: make(map[discord.UserID]*time.Timer),
 
 
-		app: app,
-		cfg: cfg,
+		app:   app,
+		cfg:   cfg,
+		token: token,
 	}
 	}
 
 
 	v.guildsTree = newGuildsTree(cfg, v)
 	v.guildsTree = newGuildsTree(cfg, v)
@@ -220,6 +222,19 @@ func (v *View) focusNext() {
 
 
 func (v *View) HandleEvent(event tcell.Event) tview.Command {
 func (v *View) HandleEvent(event tcell.Event) tview.Command {
 	switch event := event.(type) {
 	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:
 	case *tview.KeyEvent:
 		redraw := tview.RedrawCommand{}
 		redraw := tview.RedrawCommand{}
 		switch {
 		switch {

+ 14 - 0
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
+}

+ 3 - 12
internal/ui/login/form.go

@@ -20,23 +20,19 @@ const (
 	qrLayerName    = "qr"
 	qrLayerName    = "qr"
 )
 )
 
 
-type DoneFn = func(token string)
-
 type Form struct {
 type Form struct {
 	*layers.Layers
 	*layers.Layers
 	app  *tview.Application
 	app  *tview.Application
 	cfg  *config.Config
 	cfg  *config.Config
 	form *tview.Form
 	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{
 	f := &Form{
 		Layers: layers.New(),
 		Layers: layers.New(),
 		app:    app,
 		app:    app,
 		cfg:    cfg,
 		cfg:    cfg,
 		form:   tview.NewForm(),
 		form:   tview.NewForm(),
-		done:   done,
 	}
 	}
 
 
 	f.form.
 	f.form.
@@ -56,10 +52,7 @@ func (f *Form) login() {
 	}
 	}
 
 
 	go keyring.SetToken(token)
 	go keyring.SetToken(token)
-
-	if f.done != nil {
-		f.done(token)
-	}
+	f.app.QueueEvent(NewTokenEvent(token))
 }
 }
 
 
 func (f *Form) onError(err error) {
 func (f *Form) onError(err error) {
@@ -118,9 +111,7 @@ func (f *Form) loginWithQR() {
 		go keyring.SetToken(token)
 		go keyring.SetToken(token)
 
 
 		f.RemoveLayer(qrLayerName)
 		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))
 	f.AddLayer(qr, layers.WithName(qrLayerName), layers.WithResize(true), layers.WithVisible(true))

+ 14 - 36
internal/ui/root/view.go

@@ -1,8 +1,6 @@
 package root
 package root
 
 
 import (
 import (
-	"log/slog"
-
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/discordo/internal/config"
 	"github.com/ayn2op/discordo/internal/consts"
 	"github.com/ayn2op/discordo/internal/consts"
 	"github.com/ayn2op/discordo/internal/ui/chat"
 	"github.com/ayn2op/discordo/internal/ui/chat"
@@ -17,9 +15,7 @@ const tokenEnvVarKey = "DISCORDO_TOKEN"
 type View struct {
 type View struct {
 	app   *tview.Application
 	app   *tview.Application
 	inner tview.Primitive
 	inner tview.Primitive
-	chat  *chat.View
-
-	cfg *config.Config
+	cfg   *config.Config
 }
 }
 
 
 func NewView(cfg *config.Config, app *tview.Application) *View {
 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)
 var _ tview.Primitive = (*View)(nil)
@@ -75,14 +53,12 @@ func (v *View) HandleEvent(event tcell.Event) tview.Command {
 		}
 		}
 	case *tokenEvent:
 	case *tokenEvent:
 		if event.token == "" {
 		if event.token == "" {
-			v.showLoginView()
+			return tview.BatchCommand{v.showLoginView(), tview.SetFocusCommand{Target: v.inner}}
 		} else {
 		} 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:
 	case *chat.LogoutEvent:
 		v.showLoginView()
 		v.showLoginView()
 		return tview.BatchCommand{
 		return tview.BatchCommand{
@@ -96,7 +72,9 @@ func (v *View) HandleEvent(event tcell.Event) tview.Command {
 			v.suspend()
 			v.suspend()
 			return nil
 			return nil
 		case keybind.Matches(event, v.cfg.Keybinds.Quit.Keybind):
 		case keybind.Matches(event, v.cfg.Keybinds.Quit.Keybind):
-			v.closeChatViewState()
+			if v.inner != nil {
+				return v.inner.HandleEvent(chat.NewQuitEvent())
+			}
 			return tview.QuitCommand{}
 			return tview.QuitCommand{}
 		}
 		}
 	}
 	}