| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- package main
- import (
- "context"
- "sort"
- "strings"
- "github.com/99designs/keyring"
- "github.com/diamondburned/arikawa/v3/api"
- "github.com/diamondburned/arikawa/v3/discord"
- "github.com/diamondburned/arikawa/v3/gateway"
- "github.com/diamondburned/arikawa/v3/session"
- "github.com/diamondburned/arikawa/v3/state"
- "github.com/diamondburned/arikawa/v3/state/store/defaultstore"
- "github.com/gdamore/tcell/v2"
- "github.com/rigormorrtiss/discordo/ui"
- "github.com/rigormorrtiss/discordo/util"
- "github.com/rivo/tview"
- )
- var (
- app *tview.Application
- loginModal *tview.Modal
- loginForm *tview.Form
- guildsDropDown *tview.DropDown
- channelsTreeView *tview.TreeView
- channelsTreeNode *tview.TreeNode
- messagesTextView *tview.TextView
- messageInputField *tview.InputField
- mainFlex *tview.Flex
- loginVia string
- kr keyring.Keyring
- config *util.Config
- discordSession *session.Session
- discordState *state.State
- currentGuild discord.Guild
- currentChannel discord.Channel
- )
- func main() {
- tview.Borders.HorizontalFocus = tview.Borders.Horizontal
- tview.Borders.VerticalFocus = tview.Borders.Vertical
- tview.Borders.TopLeftFocus = tview.Borders.TopLeft
- tview.Borders.TopRightFocus = tview.Borders.TopRight
- tview.Borders.BottomLeftFocus = tview.Borders.BottomLeft
- tview.Borders.BottomRightFocus = tview.Borders.BottomRight
- tview.Borders.Horizontal = ' '
- tview.Borders.Vertical = ' '
- tview.Borders.TopLeft = ' '
- tview.Borders.TopRight = ' '
- tview.Borders.BottomLeft = ' '
- tview.Borders.BottomRight = ' '
- kr = util.OpenKeyringBackend()
- config = util.NewConfig()
- loginModal = ui.NewLoginModal(onLoginModalDone)
- guildsDropDown = ui.NewGuildsDropDown(onGuildsDropDownSelected, config.Theme)
- channelsTreeNode = tview.NewTreeNode("")
- channelsTreeView = ui.NewChannelsTreeView(channelsTreeNode, onChannelsTreeViewSelected, config.Theme)
- messagesTextView = ui.NewMessagesTextView(onMessagesTextViewChanged, config.Theme)
- mainFlex = ui.NewMainFlex(guildsDropDown, channelsTreeView, messagesTextView)
- app = ui.NewApp(onAppInputCapture)
- token := util.GetItem(kr, "token")
- if token != "" {
- app.
- SetRoot(mainFlex, true).
- SetFocus(guildsDropDown)
- discordSession = newSession("", "", token)
- } else {
- app.SetRoot(loginModal, true)
- }
- if err := app.Run(); err != nil {
- panic(err)
- }
- }
- func onAppInputCapture(e *tcell.EventKey) *tcell.EventKey {
- switch e.Name() {
- case "Ctrl+G":
- app.SetFocus(guildsDropDown)
- case "Ctrl+J":
- app.SetFocus(channelsTreeView)
- case "Ctrl+K":
- app.SetFocus(messagesTextView)
- case "Ctrl+L":
- if messageInputField != nil {
- app.SetFocus(messageInputField)
- }
- }
- return e
- }
- func onMessagesTextViewChanged() {
- app.Draw()
- }
- func onLoginModalDone(i int, label string) {
- if label == ui.LoginViaEmailPasswordLoginModalButton {
- loginVia = "emailpassword"
- loginForm = ui.NewLoginForm(loginVia, onLoginFormLoginButtonSelected)
- app.SetRoot(loginForm, true)
- } else if label == ui.LoginViaTokenLoginModalButton {
- loginVia = "token"
- loginForm = ui.NewLoginForm(loginVia, onLoginFormLoginButtonSelected)
- app.SetRoot(loginForm, true)
- }
- }
- func newSession(email string, password string, token string) *session.Session {
- api.UserAgent = "" +
- "Mozilla/5.0 (X11; Linux x86_64) " +
- "AppleWebKit/537.36 (KHTML, like Gecko) " +
- "Chrome/91.0.4472.164 Safari/537.36"
- gateway.DefaultIdentity.Browser = "Chrome"
- gateway.DefaultIdentity.OS = "Linux"
- var sess *session.Session
- var err error
- if email != "" && password != "" {
- sess, err = session.Login(email, password, "")
- } else if token != "" {
- sess, err = session.New(token)
- }
- if err != nil {
- panic(err)
- }
- discordState = state.NewFromSession(sess, defaultstore.New())
- sess.AddHandler(onReady)
- sess.AddHandler(onGuildCreate)
- sess.AddHandler(onMessageCreate)
- if err = sess.Open(context.Background()); err != nil {
- panic(err)
- }
- return sess
- }
- func onGuildCreate(guild *gateway.GuildCreateEvent) {
- guildsDropDown.AddOption(guild.Name, nil)
- }
- func onReady(r *gateway.ReadyEvent) {
- for i := range r.Guilds {
- guildsDropDown.AddOption(r.Guilds[i].Name, nil)
- }
- }
- func onMessageCreate(m *gateway.MessageCreateEvent) {
- if currentChannel.ID == m.ChannelID {
- util.WriteMessage(messagesTextView, discordState, m.Message)
- }
- }
- func onGuildsDropDownSelected(_ string, i int) {
- messagesTextView.SetTitle("")
- channelsTreeNode.ClearChildren()
- messagesTextView.Clear()
- if messageInputField != nil {
- mainFlex.RemoveItem(messageInputField)
- messageInputField = nil
- }
- channelsTreeView.SetTitle("Channels")
- app.SetFocus(channelsTreeView)
- currentGuild = discordState.Ready().Guilds[i].Guild
- channels, _ := discordState.Cabinet.Channels(currentGuild.ID)
- sort.SliceStable(channels, func(i, j int) bool {
- return channels[i].Position < channels[j].Position
- })
- for i := range channels {
- channel := channels[i]
- channelNode := tview.NewTreeNode(channel.Name).
- SetReference(channel)
- switch channel.Type {
- case discord.GuildCategory:
- channelNode.SetColor(tcell.GetColor(config.Theme.TreeNodeForeground))
- channelsTreeNode.AddChild(channelNode)
- case discord.GuildText, discord.GuildNews:
- if channel.CategoryID == 0 || channel.CategoryID == discord.NullChannelID {
- channelNode.SetText("[::d]#" + channel.Name + "[-:-:-]")
- channelsTreeNode.AddChild(channelNode)
- }
- }
- }
- }
- func onChannelsTreeViewSelected(n *tview.TreeNode) {
- currentChannel = n.GetReference().(discord.Channel)
- switch currentChannel.Type {
- case discord.GuildCategory:
- if len(n.GetChildren()) == 0 {
- channels, _ := discordState.Cabinet.Channels(currentGuild.ID)
- sort.SliceStable(channels, func(i, j int) bool {
- return channels[i].Position < channels[j].Position
- })
- for i := range channels {
- channel := channels[i]
- if (channel.Type == discord.GuildText || channel.Type == discord.GuildNews) && channel.CategoryID == currentChannel.ID {
- channelNode := tview.NewTreeNode("[::d]#" + channel.Name + "[-:-:-]").
- SetReference(channel)
- n.AddChild(channelNode)
- }
- }
- } else {
- n.SetExpanded(!n.IsExpanded())
- }
- case discord.GuildText, discord.GuildNews:
- if messageInputField == nil {
- messageInputField = ui.NewMessageInputField(onMessageInputFieldDone, config.Theme)
- mainFlex.AddItem(messageInputField, 3, 1, false)
- }
- app.SetFocus(messageInputField)
- messagesTextView.Clear()
- messagesTextView.SetTitle(currentChannel.Name)
- messages, _ := discordSession.Messages(currentChannel.ID, config.GetMessagesLimit)
- for i := len(messages) - 1; i >= 0; i-- {
- util.WriteMessage(messagesTextView, discordState, messages[i])
- }
- }
- }
- func onMessageInputFieldDone(k tcell.Key) {
- if k == tcell.KeyEnter {
- currentText := strings.TrimSpace(messageInputField.GetText())
- if currentText == "" {
- return
- }
- messageInputField.SetText("")
- go discordSession.SendMessage(currentChannel.ID, currentText)
- }
- }
- func onLoginFormLoginButtonSelected() {
- if loginVia == "emailpassword" {
- email := loginForm.GetFormItemByLabel("Email").(*tview.InputField).GetText()
- password := loginForm.GetFormItemByLabel("Password").(*tview.InputField).GetText()
- if email == "" || password == "" {
- return
- }
- discordSession = newSession(email, password, "")
- go util.SetItem(kr, "token", discordSession.Token)
- } else if loginVia == "token" {
- token := loginForm.GetFormItemByLabel("Token").(*tview.InputField).GetText()
- if token == "" {
- return
- }
- discordSession = newSession("", "", token)
- go util.SetItem(kr, "token", token)
- }
- app.
- SetRoot(mainFlex, true).
- SetFocus(guildsDropDown)
- }
|