Bläddra i källkod

refactor(cmd): separate chat UI widgets from application

ayn2op 5 månader sedan
förälder
incheckning
b3ac0dc6b4
6 ändrade filer med 248 tillägg och 217 borttagningar
  1. 6 151
      cmd/application.go
  2. 176 0
      cmd/chatview.go
  3. 10 10
      cmd/guilds_tree.go
  4. 20 20
      cmd/message_input.go
  5. 19 19
      cmd/messages_list.go
  6. 17 17
      cmd/state.go

+ 6 - 151
cmd/application.go

@@ -4,9 +4,7 @@ import (
 	"log/slog"
 
 	"github.com/ayn2op/discordo/internal/config"
-	"github.com/ayn2op/discordo/internal/keyring"
 	"github.com/ayn2op/discordo/internal/login"
-	"github.com/ayn2op/discordo/internal/ui"
 	"github.com/ayn2op/tview"
 	"github.com/gdamore/tcell/v2"
 	"golang.design/x/clipboard"
@@ -20,33 +18,21 @@ const (
 )
 
 type application struct {
-	cfg *config.Config
-
 	*tview.Application
-	pages        *tview.Pages
-	flex         *tview.Flex
-	guildsTree   *guildsTree
-	messagesList *messagesList
-	messageInput *messageInput
+	chatView *chatView
+	cfg      *config.Config
 }
 
 func newApplication(cfg *config.Config) *application {
 	app := &application{
-		cfg: cfg,
-
-		Application:  tview.NewApplication(),
-		pages:        tview.NewPages(),
-		flex:         tview.NewFlex(),
-		guildsTree:   newGuildsTree(cfg),
-		messagesList: newMessagesList(cfg),
-		messageInput: newMessageInput(cfg),
+		Application: tview.NewApplication(),
+		cfg:         cfg,
 	}
 
 	if err := clipboard.Init(); err != nil {
 		slog.Error("failed to init clipboard", "err", err)
 	}
 
-	app.pages.SetInputCapture(app.onPagesInputCapture)
 	app.
 		EnableMouse(cfg.Mouse).
 		SetInputCapture(app.onInputCapture).
@@ -65,12 +51,12 @@ func (a *application) run(token string) error {
 		return a.SetRoot(loginForm, true).Run()
 	}
 
+	a.chatView = newChatView(a.Application, a.cfg)
 	if err := openState(token); err != nil {
 		return err
 	}
 
-	a.init()
-	return a.SetRoot(a.pages, true).Run()
+	return a.SetRoot(a.chatView, true).Run()
 }
 
 func (a *application) quit() {
@@ -83,23 +69,6 @@ func (a *application) quit() {
 	a.Stop()
 }
 
-func (a *application) init() {
-	a.pages.Clear()
-	a.flex.Clear()
-
-	right := tview.NewFlex().
-		SetDirection(tview.FlexRow).
-		AddItem(a.messagesList, 0, 1, false).
-		AddItem(a.messageInput, 3, 1, false)
-
-	// The guilds tree is always focused first at start-up.
-	a.flex.
-		AddItem(a.guildsTree, 0, 1, true).
-		AddItem(right, 0, 4, false)
-
-	a.pages.AddAndSwitchToPage(flexPageName, a.flex, true)
-}
-
 func (a *application) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
 	switch event.Name() {
 	case a.cfg.Keys.Quit:
@@ -112,117 +81,3 @@ func (a *application) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
 
 	return event
 }
-
-func (a *application) onPagesInputCapture(event *tcell.EventKey) *tcell.EventKey {
-	switch event.Name() {
-	case a.cfg.Keys.FocusGuildsTree:
-		a.messageInput.removeMentionsList()
-		a.focusGuildsTree()
-		return nil
-	case a.cfg.Keys.FocusMessagesList:
-		a.messageInput.removeMentionsList()
-		a.SetFocus(a.messagesList)
-		return nil
-	case a.cfg.Keys.FocusMessageInput:
-		a.focusMessageInput()
-		return nil
-	case a.cfg.Keys.FocusPrevious:
-		a.focusPrevious()
-		return nil
-	case a.cfg.Keys.FocusNext:
-		a.focusNext()
-		return nil
-	case a.cfg.Keys.Logout:
-		a.quit()
-
-		if err := keyring.DeleteToken(); err != nil {
-			slog.Error("failed to delete token from keyring", "err", err)
-			return nil
-		}
-
-		return nil
-	case a.cfg.Keys.ToggleGuildsTree:
-		a.toggleGuildsTree()
-		return nil
-	}
-
-	return event
-}
-
-func (a *application) toggleGuildsTree() {
-	// The guilds tree is visible if the number of items is two.
-	if a.flex.GetItemCount() == 2 {
-		a.flex.RemoveItem(a.guildsTree)
-		if a.guildsTree.HasFocus() {
-			a.SetFocus(a.flex)
-		}
-	} else {
-		a.init()
-		a.SetFocus(a.guildsTree)
-	}
-}
-
-func (a *application) focusGuildsTree() bool {
-	// The guilds tree is not hidden if the number of items is two.
-	if a.flex.GetItemCount() == 2 {
-		a.SetFocus(a.guildsTree)
-		return true
-	}
-
-	return false
-}
-
-func (a *application) focusMessageInput() bool {
-	if !a.messageInput.GetDisabled() {
-		a.SetFocus(a.messageInput)
-		return true
-	}
-
-	return false
-}
-
-func (a *application) focusPrevious() {
-	switch a.GetFocus() {
-	case a.guildsTree:
-		a.SetFocus(a.messageInput)
-	case a.messagesList: // Handle both a.messagesList and a.flex as well as other edge cases (if there is).
-		if ok := a.focusGuildsTree(); !ok {
-			a.SetFocus(a.messageInput)
-		}
-	case a.messageInput:
-		a.SetFocus(a.messagesList)
-	}
-}
-
-func (a *application) focusNext() {
-	switch a.GetFocus() {
-	case a.guildsTree:
-		a.SetFocus(a.messagesList)
-	case a.messagesList:
-		a.SetFocus(a.messageInput)
-	case a.messageInput: // Handle both a.messageInput and a.flex as well as other edge cases (if there is).
-		if ok := a.focusGuildsTree(); !ok {
-			a.SetFocus(a.messagesList)
-		}
-	}
-}
-
-func (a *application) showConfirmModal(prompt string, buttons []string, onDone func(label string)) {
-	previousFocus := a.GetFocus()
-
-	modal := tview.NewModal().
-		SetText(prompt).
-		AddButtons(buttons).
-		SetDoneFunc(func(_ int, buttonLabel string) {
-			a.pages.RemovePage(confirmModalPageName).SwitchToPage(flexPageName)
-			a.SetFocus(previousFocus)
-
-			if onDone != nil {
-				onDone(buttonLabel)
-			}
-		})
-
-	a.pages.
-		AddAndSwitchToPage(confirmModalPageName, ui.Centered(modal, 0, 0), true).
-		ShowPage(flexPageName)
-}

+ 176 - 0
cmd/chatview.go

@@ -0,0 +1,176 @@
+package cmd
+
+import (
+	"log/slog"
+
+	"github.com/ayn2op/discordo/internal/config"
+	"github.com/ayn2op/discordo/internal/keyring"
+	"github.com/ayn2op/discordo/internal/ui"
+	"github.com/ayn2op/tview"
+	"github.com/gdamore/tcell/v2"
+)
+
+type chatView struct {
+	*tview.Pages
+
+	mainFlex  *tview.Flex
+	rightFlex *tview.Flex
+
+	guildsTree   *guildsTree
+	messagesList *messagesList
+	messageInput *messageInput
+
+	app *tview.Application
+	cfg *config.Config
+}
+
+func newChatView(app *tview.Application, cfg *config.Config) *chatView {
+	cv := &chatView{
+		Pages: tview.NewPages(),
+
+		mainFlex:  tview.NewFlex(),
+		rightFlex: tview.NewFlex(),
+
+		guildsTree:   newGuildsTree(cfg),
+		messagesList: newMessagesList(cfg),
+		messageInput: newMessageInput(cfg),
+
+		app: app,
+		cfg: cfg,
+	}
+
+	cv.SetInputCapture(cv.onInputCapture)
+
+	cv.init()
+	return cv
+}
+
+func (cv *chatView) init() {
+	cv.Clear()
+	cv.mainFlex.Clear()
+
+	cv.rightFlex.
+		SetDirection(tview.FlexRow).
+		AddItem(cv.messagesList, 0, 1, false).
+		AddItem(cv.messageInput, 3, 1, false)
+	// The guilds tree is always focused first at start-up.
+	cv.mainFlex.
+		AddItem(cv.guildsTree, 0, 1, true).
+		AddItem(cv.rightFlex, 0, 4, false)
+
+	cv.AddAndSwitchToPage(flexPageName, cv.mainFlex, true)
+}
+
+func (cv *chatView) toggleGuildsTree() {
+	// The guilds tree is visible if the number of items is two.
+	if cv.mainFlex.GetItemCount() == 2 {
+		cv.mainFlex.RemoveItem(cv.guildsTree)
+		if cv.guildsTree.HasFocus() {
+			cv.app.SetFocus(cv.mainFlex)
+		}
+	} else {
+		cv.init()
+		cv.app.SetFocus(cv.guildsTree)
+	}
+}
+
+func (cv *chatView) focusGuildsTree() bool {
+	// The guilds tree is not hidden if the number of items is two.
+	if cv.mainFlex.GetItemCount() == 2 {
+		cv.app.SetFocus(cv.guildsTree)
+		return true
+	}
+
+	return false
+}
+
+func (cv *chatView) focusMessageInput() bool {
+	if !cv.messageInput.GetDisabled() {
+		cv.app.SetFocus(cv.messageInput)
+		return true
+	}
+
+	return false
+}
+
+func (cv *chatView) focusPrevious() {
+	switch cv.app.GetFocus() {
+	case cv.guildsTree:
+		cv.app.SetFocus(cv.messageInput)
+	case cv.messagesList: // Handle both a.messagesList and a.flex as well as other edge cases (if there is).
+		if ok := cv.focusGuildsTree(); !ok {
+			cv.app.SetFocus(cv.messageInput)
+		}
+	case cv.messageInput:
+		cv.app.SetFocus(cv.messagesList)
+	}
+}
+
+func (cv *chatView) focusNext() {
+	switch cv.app.GetFocus() {
+	case cv.guildsTree:
+		cv.app.SetFocus(cv.messagesList)
+	case cv.messagesList:
+		cv.app.SetFocus(cv.messageInput)
+	case cv.messageInput: // Handle both a.messageInput and a.flex as well as other edge cases (if there is).
+		if ok := cv.focusGuildsTree(); !ok {
+			cv.app.SetFocus(cv.messagesList)
+		}
+	}
+}
+
+func (cv *chatView) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
+	switch event.Name() {
+	case cv.cfg.Keys.FocusGuildsTree:
+		cv.messageInput.removeMentionsList()
+		cv.focusGuildsTree()
+		return nil
+	case cv.cfg.Keys.FocusMessagesList:
+		cv.messageInput.removeMentionsList()
+		cv.app.SetFocus(cv.messagesList)
+		return nil
+	case cv.cfg.Keys.FocusMessageInput:
+		cv.focusMessageInput()
+		return nil
+	case cv.cfg.Keys.FocusPrevious:
+		cv.focusPrevious()
+		return nil
+	case cv.cfg.Keys.FocusNext:
+		cv.focusNext()
+		return nil
+	case cv.cfg.Keys.Logout:
+		app.quit()
+
+		if err := keyring.DeleteToken(); err != nil {
+			slog.Error("failed to delete token from keyring", "err", err)
+			return nil
+		}
+
+		return nil
+	case cv.cfg.Keys.ToggleGuildsTree:
+		cv.toggleGuildsTree()
+		return nil
+	}
+
+	return event
+}
+
+func (cv *chatView) showConfirmModal(prompt string, buttons []string, onDone func(label string)) {
+	previousFocus := cv.app.GetFocus()
+
+	modal := tview.NewModal().
+		SetText(prompt).
+		AddButtons(buttons).
+		SetDoneFunc(func(_ int, buttonLabel string) {
+			cv.RemovePage(confirmModalPageName).SwitchToPage(flexPageName)
+			cv.app.SetFocus(previousFocus)
+
+			if onDone != nil {
+				onDone(buttonLabel)
+			}
+		})
+
+	cv.
+		AddAndSwitchToPage(confirmModalPageName, ui.Centered(modal, 0, 0), true).
+		ShowPage(flexPageName)
+}

+ 10 - 10
cmd/guilds_tree.go

@@ -143,7 +143,7 @@ PARENT_CHANNELS:
 }
 
 func (gt *guildsTree) onSelected(node *tview.TreeNode) {
-	app.messageInput.reset()
+	app.chatView.messageInput.reset()
 
 	if len(node.GetChildren()) != 0 {
 		node.SetExpanded(!node.IsExpanded())
@@ -181,21 +181,21 @@ func (gt *guildsTree) onSelected(node *tview.TreeNode) {
 		}
 
 		if guildID := channel.GuildID; guildID.IsValid() {
-			app.messagesList.requestGuildMembers(guildID, messages)
+			app.chatView.messagesList.requestGuildMembers(guildID, messages)
 		}
 
-		app.messagesList.reset()
-		app.messagesList.setTitle(*channel)
-		app.messagesList.drawMessages(messages)
-		app.messagesList.ScrollToEnd()
+		app.chatView.messagesList.reset()
+		app.chatView.messagesList.setTitle(*channel)
+		app.chatView.messagesList.drawMessages(messages)
+		app.chatView.messagesList.ScrollToEnd()
 
 		hasNoPerm := channel.Type != discord.DirectMessage && channel.Type != discord.GroupDM && !discordState.HasPermissions(channel.ID, discord.PermissionSendMessages)
-		app.messageInput.SetDisabled(hasNoPerm)
+		app.chatView.messageInput.SetDisabled(hasNoPerm)
 		if hasNoPerm {
-			app.messageInput.SetPlaceholder("You do not have permission to send messages in this channel.")
+			app.chatView.messageInput.SetPlaceholder("You do not have permission to send messages in this channel.")
 		} else {
-			app.messageInput.SetPlaceholder("Message...")
-			app.SetFocus(app.messageInput)
+			app.chatView.messageInput.SetPlaceholder("Message...")
+			app.SetFocus(app.chatView.messageInput)
 		}
 
 		gt.selectedChannelID = channel.ID

+ 20 - 20
cmd/message_input.go

@@ -101,7 +101,7 @@ func (mi *messageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
 		return tcell.NewEventKey(tcell.KeyCtrlV, 0, tcell.ModNone)
 
 	case mi.cfg.Keys.MessageInput.Send:
-		if app.pages.GetVisibile(mentionsListPageName) {
+		if app.chatView.GetVisibile(mentionsListPageName) {
 			mi.tabComplete(false)
 			return nil
 		}
@@ -117,7 +117,7 @@ func (mi *messageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
 		mi.openFilePicker()
 		return nil
 	case mi.cfg.Keys.MessageInput.Cancel:
-		if app.pages.GetVisibile(mentionsListPageName) {
+		if app.chatView.GetVisibile(mentionsListPageName) {
 			mi.stopTabCompletion()
 		} else {
 			mi.reset()
@@ -130,7 +130,7 @@ func (mi *messageInput) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
 	}
 
 	if mi.cfg.AutocompleteLimit > 0 {
-		if app.pages.GetVisibile(mentionsListPageName) {
+		if app.chatView.GetVisibile(mentionsListPageName) {
 			switch event.Name() {
 			case mi.cfg.Keys.MentionsList.Up:
 				mi.mentionsList.InputHandler()(tcell.NewEventKey(tcell.KeyUp, 0, tcell.ModNone), nil)
@@ -155,7 +155,7 @@ func (mi *messageInput) paste() {
 }
 
 func (mi *messageInput) send() {
-	if !app.guildsTree.selectedChannelID.IsValid() {
+	if !app.chatView.guildsTree.selectedChannelID.IsValid() {
 		return
 	}
 
@@ -164,13 +164,13 @@ func (mi *messageInput) send() {
 		return
 	}
 
-	text = processText(app.guildsTree.selectedChannelID, []byte(text))
+	text = processText(app.chatView.guildsTree.selectedChannelID, []byte(text))
 	if text == "" {
 		return
 	}
 
 	if mi.edit {
-		m, err := app.messagesList.selectedMessage()
+		m, err := app.chatView.messagesList.selectedMessage()
 		if err != nil {
 			slog.Error("failed to get selected message", "err", err)
 			return
@@ -185,8 +185,8 @@ func (mi *messageInput) send() {
 	} else {
 		data := mi.sendMessageData
 		data.Content = text
-		if _, err := discordState.SendMessageComplex(app.guildsTree.selectedChannelID, *data); err != nil {
-			slog.Error("failed to send message in channel", "channel_id", app.guildsTree.selectedChannelID, "err", err)
+		if _, err := discordState.SendMessageComplex(app.chatView.guildsTree.selectedChannelID, *data); err != nil {
+			slog.Error("failed to send message in channel", "channel_id", app.chatView.guildsTree.selectedChannelID, "err", err)
 		}
 	}
 
@@ -198,8 +198,8 @@ func (mi *messageInput) send() {
 	}
 
 	mi.reset()
-	app.messagesList.Highlight()
-	app.messagesList.ScrollToEnd()
+	app.chatView.messagesList.Highlight()
+	app.chatView.messagesList.ScrollToEnd()
 }
 
 func processText(cID discord.ChannelID, src []byte) string {
@@ -236,7 +236,7 @@ func expandMentions(cID discord.ChannelID, src []byte) []byte {
 	return mentionRegex.ReplaceAllFunc(src, func(input []byte) []byte {
 		output := input
 		name := string(input[1:])
-		discordState.MemberStore.Each(app.guildsTree.selectedGuildID, func(m *discord.Member) bool {
+		discordState.MemberStore.Each(app.chatView.guildsTree.selectedGuildID, func(m *discord.Member) bool {
 			if strings.EqualFold(m.User.Username, name) && channelHasUser(cID, m.User.ID) {
 				output = []byte(m.User.ID.Mention())
 				return true
@@ -259,8 +259,8 @@ func (mi *messageInput) tabComplete(isAuto bool) {
 	}
 	pos := posEnd - (len(name) + 1)
 
-	gID := app.guildsTree.selectedGuildID
-	cID := app.guildsTree.selectedChannelID
+	gID := app.chatView.guildsTree.selectedGuildID
+	cID := app.chatView.guildsTree.selectedChannelID
 
 	if !isAuto {
 		if mi.cfg.AutocompleteLimit == 0 {
@@ -373,10 +373,10 @@ func (mi *messageInput) searchMember(gID discord.GuildID, name string) {
 	}
 
 	mi.lastSearch = time.Now()
-	app.messagesList.waitForChunkEvent()
-	app.messagesList.setFetchingChunk(true, 0)
+	app.chatView.messagesList.waitForChunkEvent()
+	app.chatView.messagesList.setFetchingChunk(true, 0)
 	discordState.MemberState.SearchMember(gID, name)
-	mi.cache.Create(key, app.messagesList.waitForChunkEvent())
+	mi.cache.Create(key, app.chatView.messagesList.waitForChunkEvent())
 }
 
 func (mi *messageInput) showMentionList(col int) {
@@ -387,7 +387,7 @@ func (mi *messageInput) showMentionList(col int) {
 	l := mi.mentionsList
 	x, _, _, _ := mi.GetInnerRect()
 	_, y, _, _ := mi.GetRect()
-	_, _, maxW, maxH := app.messagesList.GetInnerRect()
+	_, _, maxW, maxH := app.chatView.messagesList.GetInnerRect()
 	if t := int(mi.cfg.Theme.MentionsList.MaxHeight); t != 0 {
 		maxH = min(maxH, t)
 	}
@@ -409,7 +409,7 @@ func (mi *messageInput) showMentionList(col int) {
 
 	l.SetRect(x, y, w, h)
 
-	app.pages.
+	app.chatView.
 		AddAndSwitchToPage(mentionsListPageName, l, false).
 		ShowPage(flexPageName)
 	app.SetFocus(mi)
@@ -448,7 +448,7 @@ func (mi *messageInput) addMentionItem(gID discord.GuildID, m *discord.Member) b
 }
 
 func (mi *messageInput) removeMentionsList() {
-	app.pages.
+	app.chatView.
 		RemovePage(mentionsListPageName).
 		SwitchToPage(flexPageName)
 }
@@ -504,7 +504,7 @@ func (mi *messageInput) addTitle(s string) {
 }
 
 func (mi *messageInput) openFilePicker() {
-	if !app.guildsTree.selectedChannelID.IsValid() {
+	if !app.chatView.guildsTree.selectedChannelID.IsValid() {
 		return
 	}
 

+ 19 - 19
cmd/messages_list.go

@@ -239,7 +239,7 @@ func (ml *messagesList) selectedMessage() (*discord.Message, error) {
 		return nil, errors.New("no message is currently selected")
 	}
 
-	m, err := discordState.Cabinet.Message(app.guildsTree.selectedChannelID, ml.selectedMessageID)
+	m, err := discordState.Cabinet.Message(app.chatView.guildsTree.selectedChannelID, ml.selectedMessageID)
 	if err != nil {
 		return nil, fmt.Errorf("could not retrieve selected message: %w", err)
 	}
@@ -248,7 +248,7 @@ func (ml *messagesList) selectedMessage() (*discord.Message, error) {
 }
 
 func (ml *messagesList) selectedMessageIndex() (int, error) {
-	ms, err := discordState.Cabinet.Messages(app.guildsTree.selectedChannelID)
+	ms, err := discordState.Cabinet.Messages(app.chatView.guildsTree.selectedChannelID)
 	if err != nil {
 		return -1, err
 	}
@@ -294,9 +294,9 @@ func (ml *messagesList) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
 }
 
 func (ml *messagesList) _select(name string) {
-	ms, err := discordState.Cabinet.Messages(app.guildsTree.selectedChannelID)
+	ms, err := discordState.Cabinet.Messages(app.chatView.guildsTree.selectedChannelID)
 	if err != nil {
-		slog.Error("failed to get messages", "err", err, "channel_id", app.guildsTree.selectedChannelID)
+		slog.Error("failed to get messages", "err", err, "channel_id", app.chatView.guildsTree.selectedChannelID)
 		return
 	}
 
@@ -450,7 +450,7 @@ func (ml *messagesList) showAttachmentsList(urls []string, attachments []discord
 		SetHighlightFullLine(true).
 		ShowSecondaryText(false).
 		SetDoneFunc(func() {
-			app.pages.RemovePage(attachmentsListPageName).SwitchToPage(flexPageName)
+			app.chatView.RemovePage(attachmentsListPageName).SwitchToPage(flexPageName)
 			app.SetFocus(ml)
 		})
 	list.
@@ -486,7 +486,7 @@ func (ml *messagesList) showAttachmentsList(urls []string, attachments []discord
 		})
 	}
 
-	app.pages.
+	app.chatView.
 		AddAndSwitchToPage(attachmentsListPageName, ui.Centered(list, 0, 0), true).
 		ShowPage(flexPageName)
 }
@@ -548,7 +548,7 @@ func (ml *messagesList) reply(mention bool) {
 		}
 	}
 
-	data := app.messageInput.sendMessageData
+	data := app.chatView.messageInput.sendMessageData
 	data.Reference = &discord.MessageReference{MessageID: ml.selectedMessageID}
 	data.AllowedMentions = &api.AllowedMentions{RepliedUser: option.False}
 
@@ -558,9 +558,9 @@ func (ml *messagesList) reply(mention bool) {
 		title = "[@] " + title
 	}
 
-	app.messageInput.sendMessageData = data
-	app.messageInput.addTitle(title + name)
-	app.SetFocus(app.messageInput)
+	app.chatView.messageInput.sendMessageData = data
+	app.chatView.messageInput.addTitle(title + name)
+	app.SetFocus(app.chatView.messageInput)
 }
 
 func (ml *messagesList) edit() {
@@ -581,10 +581,10 @@ func (ml *messagesList) edit() {
 		return
 	}
 
-	app.messageInput.SetTitle("Editing")
-	app.messageInput.edit = true
-	app.messageInput.SetText(message.Content, true)
-	app.SetFocus(app.messageInput)
+	app.chatView.messageInput.SetTitle("Editing")
+	app.chatView.messageInput.edit = true
+	app.chatView.messageInput.SetText(message.Content, true)
+	app.SetFocus(app.chatView.messageInput)
 }
 
 func (ml *messagesList) confirmDelete() {
@@ -594,7 +594,7 @@ func (ml *messagesList) confirmDelete() {
 		}
 	}
 
-	app.showConfirmModal(
+	app.chatView.showConfirmModal(
 		"Are you sure you want to delete this message?",
 		[]string{"Yes", "No"},
 		onChoice,
@@ -621,16 +621,16 @@ func (ml *messagesList) delete() {
 		}
 	}
 
-	if err := discordState.DeleteMessage(app.guildsTree.selectedChannelID, msg.ID, ""); err != nil {
-		slog.Error("failed to delete message", "channel_id", app.guildsTree.selectedChannelID, "message_id", msg.ID, "err", err)
+	if err := discordState.DeleteMessage(app.chatView.guildsTree.selectedChannelID, msg.ID, ""); err != nil {
+		slog.Error("failed to delete message", "channel_id", app.chatView.guildsTree.selectedChannelID, "message_id", msg.ID, "err", err)
 		return
 	}
 
 	ml.selectedMessageID = 0
 	ml.Highlight()
 
-	if err := discordState.MessageRemove(app.guildsTree.selectedChannelID, msg.ID); err != nil {
-		slog.Error("failed to delete message", "channel_id", app.guildsTree.selectedChannelID, "message_id", msg.ID, "err", err)
+	if err := discordState.MessageRemove(app.chatView.guildsTree.selectedChannelID, msg.ID); err != nil {
+		slog.Error("failed to delete message", "channel_id", app.chatView.guildsTree.selectedChannelID, "message_id", msg.ID, "err", err)
 		return
 	}
 

+ 17 - 17
cmd/state.go

@@ -45,11 +45,11 @@ func openState(token string) error {
 	discordState.AddHandler(onReadUpdate)
 
 	discordState.AddHandler(func(event *gateway.GuildMembersChunkEvent) {
-		app.messagesList.setFetchingChunk(false, uint(len(event.Members)))
+		app.chatView.messagesList.setFetchingChunk(false, uint(len(event.Members)))
 	})
 
 	discordState.AddHandler(func(event *gateway.GuildMemberRemoveEvent) {
-		app.messageInput.cache.Invalidate(event.GuildID.String()+" "+event.User.Username, discordState.MemberState.SearchLimit)
+		app.chatView.messageInput.cache.Invalidate(event.GuildID.String()+" "+event.User.Username, discordState.MemberState.SearchLimit)
 	})
 
 	discordState.StateLog = func(err error) {
@@ -79,18 +79,18 @@ func onRaw(event *ws.RawEvent) {
 
 func onReadUpdate(event *read.UpdateEvent) {
 	var guildNode *tview.TreeNode
-	app.guildsTree.
+	app.chatView.guildsTree.
 		GetRoot().
 		Walk(func(node, parent *tview.TreeNode) bool {
 			switch node.GetReference() {
 			case event.GuildID:
-				node.SetTextStyle(app.guildsTree.getGuildNodeStyle(event.GuildID))
+				node.SetTextStyle(app.chatView.guildsTree.getGuildNodeStyle(event.GuildID))
 				guildNode = node
 				return false
 			case event.ChannelID:
 				// private channel
 				if !event.GuildID.IsValid() {
-					style := app.guildsTree.getChannelNodeStyle(event.ChannelID)
+					style := app.chatView.guildsTree.getChannelNodeStyle(event.ChannelID)
 					node.SetTextStyle(style)
 					return false
 				}
@@ -102,7 +102,7 @@ func onReadUpdate(event *read.UpdateEvent) {
 	if guildNode != nil {
 		guildNode.Walk(func(node, parent *tview.TreeNode) bool {
 			if node.GetReference() == event.ChannelID {
-				node.SetTextStyle(app.guildsTree.getChannelNodeStyle(event.ChannelID))
+				node.SetTextStyle(app.chatView.guildsTree.getChannelNodeStyle(event.ChannelID))
 				return false
 			}
 
@@ -115,7 +115,7 @@ func onReadUpdate(event *read.UpdateEvent) {
 
 func onReady(r *gateway.ReadyEvent) {
 	dmNode := tview.NewTreeNode("Direct Messages")
-	root := app.guildsTree.
+	root := app.chatView.guildsTree.
 		GetRoot().
 		ClearChildren().
 		AddChild(dmNode)
@@ -134,20 +134,20 @@ func onReady(r *gateway.ReadyEvent) {
 				continue
 			}
 
-			app.guildsTree.createGuildNode(root, *guild)
+			app.chatView.guildsTree.createGuildNode(root, *guild)
 		} else {
-			app.guildsTree.createFolderNode(folder)
+			app.chatView.guildsTree.createFolderNode(folder)
 		}
 	}
 
-	app.guildsTree.SetCurrentNode(root)
-	app.SetFocus(app.guildsTree)
+	app.chatView.guildsTree.SetCurrentNode(root)
+	app.SetFocus(app.chatView.guildsTree)
 	app.Draw()
 }
 
 func onMessageCreate(message *gateway.MessageCreateEvent) {
-	if app.guildsTree.selectedChannelID == message.ChannelID {
-		app.messagesList.drawMessage(app.messagesList, message.Message)
+	if app.chatView.guildsTree.selectedChannelID == message.ChannelID {
+		app.chatView.messagesList.drawMessage(app.chatView.messagesList, message.Message)
 		app.Draw()
 	}
 
@@ -157,21 +157,21 @@ func onMessageCreate(message *gateway.MessageCreateEvent) {
 }
 
 func onMessageUpdate(message *gateway.MessageUpdateEvent) {
-	if app.guildsTree.selectedChannelID == message.ChannelID {
+	if app.chatView.guildsTree.selectedChannelID == message.ChannelID {
 		onMessageDelete(&gateway.MessageDeleteEvent{ID: message.ID, ChannelID: message.ChannelID, GuildID: message.GuildID})
 	}
 }
 
 func onMessageDelete(message *gateway.MessageDeleteEvent) {
-	if app.guildsTree.selectedChannelID == message.ChannelID {
+	if app.chatView.guildsTree.selectedChannelID == message.ChannelID {
 		messages, err := discordState.Cabinet.Messages(message.ChannelID)
 		if err != nil {
 			slog.Error("failed to get messages from state", "err", err, "channel_id", message.ChannelID)
 			return
 		}
 
-		app.messagesList.reset()
-		app.messagesList.drawMessages(messages)
+		app.chatView.messagesList.reset()
+		app.chatView.messagesList.drawMessages(messages)
 		app.Draw()
 	}
 }