| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- package root
- import (
- "log/slog"
- "os"
- "github.com/ayn2op/discordo/internal/config"
- "github.com/ayn2op/discordo/internal/consts"
- "github.com/ayn2op/discordo/internal/ui/chat"
- "github.com/ayn2op/discordo/internal/ui/login"
- "github.com/ayn2op/discordo/internal/ui/login/qr"
- "github.com/ayn2op/discordo/internal/ui/login/token"
- "github.com/ayn2op/tview"
- "github.com/ayn2op/tview/flex"
- "github.com/ayn2op/tview/help"
- "github.com/ayn2op/tview/keybind"
- "github.com/gdamore/tcell/v3"
- )
- const tokenEnvVarKey = "DISCORDO_TOKEN"
- type Model struct {
- app *tview.Application
- rootFlex *flex.Model // inner + help
- inner tview.Model
- help *help.Help
- cfg *config.Config
- }
- func NewModel(cfg *config.Config, app *tview.Application) *Model {
- m := &Model{
- app: app,
- rootFlex: flex.NewModel(),
- help: help.New(),
- cfg: cfg,
- }
- m.rootFlex.SetDirection(flex.DirectionRow)
- styles := help.DefaultStyles()
- styles.ShortKeyStyle = cfg.Theme.Help.ShortKeyStyle.Style
- styles.ShortDescStyle = cfg.Theme.Help.ShortDescStyle.Style
- styles.FullKeyStyle = cfg.Theme.Help.FullKeyStyle.Style
- styles.FullDescStyle = cfg.Theme.Help.FullDescStyle.Style
- m.help.SetStyles(styles)
- m.help.SetKeyMap(m)
- m.help.SetCompactModifiers(cfg.Help.CompactModifiers)
- m.help.SetShortSeparator(cfg.Help.Separator)
- m.help.SetBorderPadding(0, 0, cfg.Help.Padding[0], cfg.Help.Padding[1])
- m.buildLayout()
- return m
- }
- func (m *Model) showLogin() tview.Command {
- m.inner = login.NewModel(m.cfg)
- m.buildLayout()
- return tview.Batch(m.inner.HandleEvent(&tview.InitEvent{}), tview.SetFocus(m))
- }
- func (m *Model) showChat(token string) tview.Command {
- m.inner = chat.NewModel(m.app, m.cfg, token)
- m.buildLayout()
- return tview.Batch(m.inner.HandleEvent(&tview.InitEvent{}), tview.SetFocus(m))
- }
- func (m *Model) buildLayout() {
- m.rootFlex.Clear()
- if m.inner != nil {
- m.rootFlex.AddItem(m.inner, 0, 1, true)
- }
- m.rootFlex.AddItem(m.help, 1, 0, false)
- m.updateHelpHeight()
- }
- var _ tview.Model = (*Model)(nil)
- func (m *Model) Draw(screen tcell.Screen) {
- m.rootFlex.Draw(screen)
- }
- func (m *Model) HandleEvent(event tview.Event) tview.Command {
- switch event := event.(type) {
- case *tview.InitEvent:
- var cmd tview.Command
- if token := os.Getenv(tokenEnvVarKey); token != "" {
- cmd = tokenCommand(token)
- } else {
- cmd = getToken()
- }
- return tview.Batch(
- tview.SetTitle(consts.Name),
- initClipboard(),
- cmd,
- )
- case *loginEvent:
- return m.showLogin()
- case *tokenEvent:
- return m.showChat(event.token)
- case *token.TokenEvent:
- return tview.Batch(m.showChat(event.Token), setToken(event.Token))
- case *qr.TokenEvent:
- return tview.Batch(m.showChat(event.Token), setToken(event.Token))
- case *chat.LogoutEvent:
- return tview.Batch(
- m.showLogin(),
- deleteToken(),
- )
- case *tview.KeyEvent:
- switch {
- case keybind.Matches(event, m.cfg.Keybinds.ToggleHelp.Keybind):
- m.help.SetShowAll(!m.help.ShowAll())
- m.updateHelpHeight()
- return nil
- case m.help.ShowAll() && keybind.Matches(event, m.cfg.Keybinds.EditConfig.Keybind):
- m.editConfig()
- return nil
- case keybind.Matches(event, m.cfg.Keybinds.Suspend.Keybind):
- m.suspend()
- return nil
- case keybind.Matches(event, m.cfg.Keybinds.Quit.Keybind):
- var innerCmd tview.Command
- if m.inner != nil {
- innerCmd = m.inner.HandleEvent(&chat.QuitEvent{})
- }
- return tview.Batch(innerCmd, tview.Quit())
- }
- }
- if m.inner != nil {
- return m.inner.HandleEvent(event)
- }
- return nil
- }
- func (m *Model) editConfig() {
- cmd := m.cfg.CreateEditorCommand(m.cfg.Path)
- if cmd == nil {
- return
- }
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- m.app.Suspend(func() {
- if err := cmd.Run(); err != nil {
- slog.Error("failed to run editor", "args", cmd.Args, "err", err)
- }
- })
- }
- func (m *Model) updateHelpHeight() {
- height := 1
- if m.help.ShowAll() {
- height = max(len(m.help.FullHelpLines(m.FullHelp(), 0)), 1)
- }
- m.rootFlex.ResizeItem(m.help, height, 0)
- }
- func (m *Model) Rect() (int, int, int, int) {
- return m.rootFlex.Rect()
- }
- func (m *Model) SetRect(x int, y int, width int, height int) {
- m.rootFlex.SetRect(x, y, width, height)
- }
- func (m *Model) Focus(delegate func(tview.Model)) {
- if m.inner != nil {
- delegate(m.inner)
- }
- }
- func (m *Model) HasFocus() bool {
- if m.inner != nil {
- return m.inner.HasFocus()
- }
- return true
- }
- func (m *Model) Blur() {
- if m.inner != nil {
- m.inner.Blur()
- }
- }
|