197 lines
3.8 KiB
Go
197 lines
3.8 KiB
Go
package root
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
|
|
"github.com/ayn2op/discordo/internal/clipboard"
|
|
"github.com/ayn2op/discordo/internal/config"
|
|
"github.com/ayn2op/discordo/internal/consts"
|
|
"github.com/ayn2op/discordo/internal/keyring"
|
|
"github.com/ayn2op/discordo/internal/ui/chat"
|
|
"github.com/ayn2op/discordo/internal/ui/login"
|
|
"github.com/ayn2op/tview"
|
|
"github.com/ayn2op/tview/keybind"
|
|
"github.com/gdamore/tcell/v3"
|
|
)
|
|
|
|
type View struct {
|
|
*tview.Box
|
|
app *tview.Application
|
|
inner tview.Primitive
|
|
chat *chat.View
|
|
|
|
cfg *config.Config
|
|
}
|
|
|
|
func NewView(cfg *config.Config) *View {
|
|
tview.Styles = tview.Theme{}
|
|
v := &View{
|
|
Box: tview.NewBox(),
|
|
app: tview.NewApplication(),
|
|
cfg: cfg,
|
|
}
|
|
|
|
if err := clipboard.Init(); err != nil {
|
|
slog.Error("failed to init clipboard", "err", err)
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func (v *View) Run() error {
|
|
token := os.Getenv("DISCORDO_TOKEN")
|
|
if token == "" {
|
|
t, err := keyring.GetToken()
|
|
if err != nil {
|
|
slog.Info("failed to retrieve token from keyring", "err", err)
|
|
}
|
|
token = t
|
|
}
|
|
|
|
screen, err := tcell.NewScreen()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create screen: %w", err)
|
|
}
|
|
|
|
if err := screen.Init(); err != nil {
|
|
return fmt.Errorf("failed to init screen: %w", err)
|
|
}
|
|
|
|
if v.cfg.Mouse {
|
|
screen.EnableMouse()
|
|
}
|
|
|
|
screen.SetTitle(consts.Name)
|
|
screen.EnablePaste()
|
|
screen.EnableFocus()
|
|
v.app.SetScreen(screen)
|
|
v.app.SetRoot(v)
|
|
|
|
if token == "" {
|
|
v.showLoginView()
|
|
} else {
|
|
if err := v.showChatView(token); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
v.app.SetFocus(v)
|
|
err = v.app.Run()
|
|
v.closeChatViewState()
|
|
return err
|
|
}
|
|
|
|
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.inner = loginForm
|
|
v.MarkDirty()
|
|
v.app.SetFocus(v)
|
|
}
|
|
|
|
func (v *View) showChatView(token string) error {
|
|
v.chat = chat.NewView(v.app, v.cfg, v.showLoginView)
|
|
if err := v.chat.OpenState(token); err != nil {
|
|
return err
|
|
}
|
|
v.inner = v.chat
|
|
v.MarkDirty()
|
|
v.app.SetFocus(v)
|
|
return nil
|
|
}
|
|
|
|
func (v *View) quit() {
|
|
v.closeChatViewState()
|
|
v.app.Stop()
|
|
}
|
|
|
|
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) Draw(screen tcell.Screen) {
|
|
if v.inner == nil {
|
|
return
|
|
}
|
|
x, y, width, height := v.GetRect()
|
|
v.inner.SetRect(x, y, width, height)
|
|
v.inner.Draw(screen)
|
|
}
|
|
|
|
func (v *View) InputHandler(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
|
|
switch {
|
|
case keybind.Matches(event, v.cfg.Keybinds.Suspend.Keybind):
|
|
v.suspend()
|
|
return
|
|
case keybind.Matches(event, v.cfg.Keybinds.Quit.Keybind):
|
|
v.quit()
|
|
return
|
|
}
|
|
|
|
if v.inner != nil {
|
|
v.inner.InputHandler(event, setFocus)
|
|
}
|
|
}
|
|
|
|
func (v *View) Focus(delegate func(p tview.Primitive)) {
|
|
if v.inner != nil {
|
|
delegate(v.inner)
|
|
return
|
|
}
|
|
v.Box.Focus(delegate)
|
|
}
|
|
|
|
func (v *View) HasFocus() bool {
|
|
if v.inner != nil && v.inner.HasFocus() {
|
|
return true
|
|
}
|
|
return v.Box.HasFocus()
|
|
}
|
|
|
|
func (v *View) Blur() {
|
|
if v.inner != nil {
|
|
v.inner.Blur()
|
|
}
|
|
v.Box.Blur()
|
|
}
|
|
|
|
func (v *View) MouseHandler(action tview.MouseAction, event *tcell.EventMouse, setFocus func(p tview.Primitive)) (consumed bool, capture tview.Primitive) {
|
|
if v.inner == nil {
|
|
return false, nil
|
|
}
|
|
return v.inner.MouseHandler(action, event, setFocus)
|
|
}
|
|
|
|
func (v *View) PasteHandler(text string, setFocus func(p tview.Primitive)) {
|
|
if v.inner == nil {
|
|
return
|
|
}
|
|
v.inner.PasteHandler(text, setFocus)
|
|
}
|
|
|
|
func (v *View) IsDirty() bool {
|
|
if v.Box.IsDirty() {
|
|
return true
|
|
}
|
|
if v.inner == nil {
|
|
return false
|
|
}
|
|
return v.inner.IsDirty()
|
|
}
|
|
|
|
func (v *View) MarkClean() {
|
|
v.Box.MarkClean()
|
|
if v.inner != nil {
|
|
v.inner.MarkClean()
|
|
}
|
|
}
|