diff --git a/config/config.go b/config/config.go deleted file mode 100644 index 5bbe4fe..0000000 --- a/config/config.go +++ /dev/null @@ -1,41 +0,0 @@ -package config - -var General = struct { - UserAgent string - Mouse bool - Notifications bool - FetchMessagesLimit int -}{ - UserAgent: "Mozilla/5.0 (X11; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0", - Mouse: true, - Notifications: true, - FetchMessagesLimit: 50, -} - -var Keybindings = struct { - FocusChannelsTreeView []string - FocusMessagesView []string - FocusMessageInputField []string - - SelectPreviousMessage []string - SelectNextMessage []string - SelectFirstMessage []string - SelectLastMessage []string - SelectMessageReference []string - ReplySelectedMessage []string - MentionReplySelectedMessage []string - CopySelectedMessage []string -}{ - FocusChannelsTreeView: []string{"Alt+Left"}, - FocusMessagesView: []string{"Alt+Right"}, - FocusMessageInputField: []string{"Alt+Down"}, - - SelectPreviousMessage: []string{"Up"}, - SelectNextMessage: []string{"Down"}, - SelectFirstMessage: []string{"Home"}, - SelectLastMessage: []string{"End"}, - ReplySelectedMessage: []string{"Rune[r]"}, - MentionReplySelectedMessage: []string{"Rune[R]"}, - CopySelectedMessage: []string{"Rune[c]"}, - SelectMessageReference: []string{"Rune[m]"}, -} diff --git a/config/mod.go b/config/mod.go new file mode 100644 index 0000000..9c113ee --- /dev/null +++ b/config/mod.go @@ -0,0 +1,91 @@ +package config + +import ( + "encoding/json" + "os" +) + +type GeneralConfig struct { + UserAgent string `json:"userAgent"` + FetchMessagesLimit int `json:"fetchMessagesLimit"` + Mouse bool `json:"mouse"` + Notifications bool `json:"notifications"` +} + +type KeybindingsConfig struct { + FocusChannelsTreeView []string `json:"focusChannelsTreeView"` + FocusMessagesTextView []string `json:"focusMessagesTextView"` + FocusMessageInputField []string `json:"focusMessageInputField"` + + SelectPreviousMessage []string `json:"selectPreviousMessage"` + SelectNextMessage []string `json:"selectNextMessage"` + SelectFirstMessage []string `json:"selectFirstMessage"` + SelectLastMessage []string `json:"selectLastMessage"` + SelectMessageReference []string `json:"selectMessageReference"` + ReplySelectedMessage []string `json:"replySelectedMessage"` + MentionReplySelectedMessage []string `json:"mentionReplySelectedMessage"` + CopySelectedMessage []string `json:"copySelectedMessage"` +} + +type Config struct { + General GeneralConfig `json:"general"` + Keybindings KeybindingsConfig `json:"keybindings"` +} + +func New() *Config { + return &Config{ + General: GeneralConfig{ + UserAgent: "Mozilla/5.0 (X11; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0", + FetchMessagesLimit: 50, + Mouse: true, + Notifications: true, + }, + Keybindings: KeybindingsConfig{ + FocusChannelsTreeView: []string{"Alt+Left"}, + FocusMessagesTextView: []string{"Alt+Right"}, + FocusMessageInputField: []string{"Alt+Down"}, + + SelectPreviousMessage: []string{"Up"}, + SelectNextMessage: []string{"Down"}, + SelectFirstMessage: []string{"Home"}, + SelectLastMessage: []string{"End"}, + SelectMessageReference: []string{"Rune[m]"}, + ReplySelectedMessage: []string{"Rune[r]"}, + MentionReplySelectedMessage: []string{"Rune[R]"}, + CopySelectedMessage: []string{"Rune[c]"}, + }, + } +} + +func (c *Config) Load() { + configPath, err := os.UserConfigDir() + if err != nil { + panic(err) + } + + configPath += "/discordo.json" + f, err := os.OpenFile(configPath, os.O_CREATE|os.O_RDWR, os.ModePerm) + if err != nil { + panic(err) + } + + fi, err := f.Stat() + if err != nil { + panic(err) + } + // If the size of the file is zero (the file is empty), write the default configuration to the file. + if fi.Size() == 0 { + e := json.NewEncoder(f) + e.SetIndent("", "\t") + + err = e.Encode(c) + if err != nil { + panic(err) + } + } else { + err = json.NewDecoder(f).Decode(&c) + if err != nil { + panic(err) + } + } +} diff --git a/main.go b/main.go index 4deb130..74aa4e8 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,6 @@ import ( "os" "github.com/ayntgl/discordgo" - "github.com/ayntgl/discordo/config" "github.com/ayntgl/discordo/ui" "github.com/rivo/tview" "github.com/zalando/go-keyring" @@ -15,7 +14,7 @@ const service = "discordo" func main() { app := ui.NewApp() - app.EnableMouse(config.General.Mouse) + app.Config.Load() token := os.Getenv("DISCORDO_TOKEN") if token == "" { @@ -28,9 +27,8 @@ func main() { panic(err) } - ui.DrawMainFlex(app) app. - SetRoot(app.MainFlex, true). + SetRoot(ui.NewMainFlex(app), true). SetFocus(app.GuildsList) } else { app.LoginForm = ui.NewLoginForm(func() { @@ -39,7 +37,7 @@ func main() { app.SetRoot(app.LoginForm, true) } - if err := app.Run(); err != nil { + if err := app.EnableMouse(app.Config.General.Mouse).Run(); err != nil { panic(err) } } @@ -59,7 +57,7 @@ func onLoginFormLoginButtonSelected(app *ui.App) { if lr.Token != "" && !lr.MFA { app. - SetRoot(app.MainFlex, true). + SetRoot(ui.NewMainFlex(app), true). SetFocus(app.GuildsList) err = app.Connect(lr.Token) @@ -82,7 +80,7 @@ func onLoginFormLoginButtonSelected(app *ui.App) { } app. - SetRoot(app.MainFlex, true). + SetRoot(ui.NewMainFlex(app), true). SetFocus(app.GuildsList) err = app.Connect(lr.Token) diff --git a/ui/app.go b/ui/app.go index 7788f15..7d8e18c 100644 --- a/ui/app.go +++ b/ui/app.go @@ -14,7 +14,6 @@ type App struct { *tview.Application LoginForm *tview.Form - MainFlex *tview.Flex GuildsList *tview.List ChannelsTreeView *tview.TreeView MessagesTextView *tview.TextView @@ -23,15 +22,14 @@ type App struct { Session *discordgo.Session SelectedChannel *discordgo.Channel SelectedMessage int + Config *config.Config } func NewApp() *App { s, _ := discordgo.New() return &App{ - Application: tview.NewApplication(), - + Application: tview.NewApplication(), LoginForm: tview.NewForm(), - MainFlex: tview.NewFlex(), GuildsList: tview.NewList(), ChannelsTreeView: tview.NewTreeView(), MessagesTextView: tview.NewTextView(), @@ -39,12 +37,13 @@ func NewApp() *App { Session: s, SelectedMessage: -1, + Config: config.New(), } } func (app *App) Connect(token string) error { app.Session.Token = token - app.Session.UserAgent = config.General.UserAgent + app.Session.UserAgent = app.Config.General.UserAgent app.Session.Identify = discordgo.Identify{ Token: token, @@ -85,7 +84,7 @@ func (app *App) onSessionReady(_ *discordgo.Session, r *discordgo.Ready) { func (app *App) onSessionMessageCreate(_ *discordgo.Session, m *discordgo.MessageCreate) { if app.SelectedChannel == nil || app.SelectedChannel.ID != m.ChannelID { - if config.General.Notifications { + if app.Config.General.Notifications { for _, u := range m.Mentions { if u.ID == app.Session.State.User.ID { g, err := app.Session.State.Guild(m.GuildID) diff --git a/ui/handlers.go b/ui/handlers.go index 427b77c..7db8297 100644 --- a/ui/handlers.go +++ b/ui/handlers.go @@ -6,20 +6,19 @@ import ( "github.com/atotto/clipboard" "github.com/ayntgl/discordgo" - "github.com/ayntgl/discordo/config" "github.com/ayntgl/discordo/util" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) func onAppInputCapture(app *App, e *tcell.EventKey) *tcell.EventKey { - if hasKeybinding(config.Keybindings.FocusChannelsTreeView, e.Name()) { + if hasKeybinding(app.Config.Keybindings.FocusChannelsTreeView, e.Name()) { app.SetFocus(app.ChannelsTreeView) return nil - } else if hasKeybinding(config.Keybindings.FocusMessagesView, e.Name()) { + } else if hasKeybinding(app.Config.Keybindings.FocusMessagesTextView, e.Name()) { app.SetFocus(app.MessagesTextView) return nil - } else if hasKeybinding(config.Keybindings.FocusMessageInputField, e.Name()) { + } else if hasKeybinding(app.Config.Keybindings.FocusMessageInputField, e.Name()) { app.SetFocus(app.MessageInputField) return nil } @@ -121,7 +120,7 @@ func onChannelsTreeViewSelected(app *App, n *tview.TreeNode) { app.SetFocus(app.MessageInputField) go func() { - ms, err := app.Session.ChannelMessages(c.ID, config.General.FetchMessagesLimit, "", "", "") + ms, err := app.Session.ChannelMessages(c.ID, app.Config.General.FetchMessagesLimit, "", "", "") if err != nil { return } @@ -145,7 +144,7 @@ func onMessagesTextViewInputCapture(app *App, e *tcell.EventKey) *tcell.EventKey return nil } - if hasKeybinding(config.Keybindings.SelectPreviousMessage, e.Name()) { + if hasKeybinding(app.Config.Keybindings.SelectPreviousMessage, e.Name()) { if len(app.MessagesTextView.GetHighlights()) == 0 { app.SelectedMessage = len(ms) - 1 } else { @@ -159,7 +158,7 @@ func onMessagesTextViewInputCapture(app *App, e *tcell.EventKey) *tcell.EventKey Highlight(ms[app.SelectedMessage].ID). ScrollToHighlight() return nil - } else if hasKeybinding(config.Keybindings.SelectNextMessage, e.Name()) { + } else if hasKeybinding(app.Config.Keybindings.SelectNextMessage, e.Name()) { if len(app.MessagesTextView.GetHighlights()) == 0 { app.SelectedMessage = len(ms) - 1 } else { @@ -173,19 +172,19 @@ func onMessagesTextViewInputCapture(app *App, e *tcell.EventKey) *tcell.EventKey Highlight(ms[app.SelectedMessage].ID). ScrollToHighlight() return nil - } else if hasKeybinding(config.Keybindings.SelectFirstMessage, e.Name()) { + } else if hasKeybinding(app.Config.Keybindings.SelectFirstMessage, e.Name()) { app.SelectedMessage = 0 app.MessagesTextView. Highlight(ms[app.SelectedMessage].ID). ScrollToHighlight() return nil - } else if hasKeybinding(config.Keybindings.SelectLastMessage, e.Name()) { + } else if hasKeybinding(app.Config.Keybindings.SelectLastMessage, e.Name()) { app.SelectedMessage = len(ms) - 1 app.MessagesTextView. Highlight(ms[app.SelectedMessage].ID). ScrollToHighlight() return nil - } else if hasKeybinding(config.Keybindings.SelectMessageReference, e.Name()) { + } else if hasKeybinding(app.Config.Keybindings.SelectMessageReference, e.Name()) { hs := app.MessagesTextView.GetHighlights() if len(hs) == 0 { return nil @@ -200,7 +199,7 @@ func onMessagesTextViewInputCapture(app *App, e *tcell.EventKey) *tcell.EventKey } return nil - } else if hasKeybinding(config.Keybindings.ReplySelectedMessage, e.Name()) { + } else if hasKeybinding(app.Config.Keybindings.ReplySelectedMessage, e.Name()) { hs := app.MessagesTextView.GetHighlights() if len(hs) == 0 { return nil @@ -210,7 +209,7 @@ func onMessagesTextViewInputCapture(app *App, e *tcell.EventKey) *tcell.EventKey app.MessageInputField.SetTitle("Replying to " + m.Author.String()) app.SetFocus(app.MessageInputField) return nil - } else if hasKeybinding(config.Keybindings.MentionReplySelectedMessage, e.Name()) { + } else if hasKeybinding(app.Config.Keybindings.MentionReplySelectedMessage, e.Name()) { hs := app.MessagesTextView.GetHighlights() if len(hs) == 0 { return nil @@ -220,7 +219,7 @@ func onMessagesTextViewInputCapture(app *App, e *tcell.EventKey) *tcell.EventKey app.MessageInputField.SetTitle("[@] Replying to " + m.Author.String()) app.SetFocus(app.MessageInputField) return nil - } else if hasKeybinding(config.Keybindings.CopySelectedMessage, e.Name()) { + } else if hasKeybinding(app.Config.Keybindings.CopySelectedMessage, e.Name()) { hs := app.MessagesTextView.GetHighlights() if len(hs) == 0 { return nil diff --git a/ui/views.go b/ui/views.go index d91d3c9..b921fc0 100644 --- a/ui/views.go +++ b/ui/views.go @@ -5,7 +5,7 @@ import ( "github.com/rivo/tview" ) -func DrawMainFlex(app *App) { +func NewMainFlex(app *App) *tview.Flex { app.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey { return onAppInputCapture(app, e) }) @@ -63,7 +63,7 @@ func DrawMainFlex(app *App) { AddItem(app.MessagesTextView, 0, 1, false). AddItem(app.MessageInputField, 3, 1, false) - app.MainFlex. + return tview.NewFlex(). AddItem(leftFlex, 0, 1, false). AddItem(rightFlex, 0, 4, false) } diff --git a/util/ui.go b/util/ui.go index 07f1cdd..dc5f7c3 100644 --- a/util/ui.go +++ b/util/ui.go @@ -7,7 +7,6 @@ import ( "github.com/rivo/tview" ) -// GetNodeByReference walks the root `*TreeNode` of the given `*TreeView` *treeView* and returns the TreeNode whose reference is equal to the given reference *r*. If the `*TreeNode` is not found, `nil` is returned instead. func GetNodeByReference(treeView *tview.TreeView, r interface{}) (mn *tview.TreeNode) { treeView.GetRoot().Walk(func(n, _ *tview.TreeNode) bool { if n.GetReference() == r { @@ -21,7 +20,6 @@ func GetNodeByReference(treeView *tview.TreeView, r interface{}) (mn *tview.Tree return } -// ChannelToString constructs a string representation of the given channel. The string representation may vary for different channel types. func ChannelToString(c *discordgo.Channel) string { var repr string if c.Name != "" { @@ -41,7 +39,6 @@ func ChannelToString(c *discordgo.Channel) string { return repr } -// CreateChannelNode builds (encorporates unread channels in bold tag, otherwise dim, etc.) and returns a node according to the type of the given channel *c*. func CreateChannelNode(s *discordgo.State, c *discordgo.Channel) *tview.TreeNode { var cn *tview.TreeNode switch c.Type {