ayn2op преди 3 години
ревизия
f96e4a5f0d
променени са 9 файла, в които са добавени 357 реда и са изтрити 0 реда
  1. 18 0
      channels_tree.go
  2. 68 0
      config.go
  3. 23 0
      go.mod
  4. 39 0
      go.sum
  5. 45 0
      guilds_tree.go
  6. 70 0
      main.go
  7. 18 0
      message_input.go
  8. 23 0
      messages_text.go
  9. 53 0
      state.go

+ 18 - 0
channels_tree.go

@@ -0,0 +1,18 @@
+package main
+
+import "github.com/rivo/tview"
+
+type ChannelsTree struct {
+	*tview.TreeView
+}
+
+func newChannelsTree() *ChannelsTree {
+	ct := &ChannelsTree{
+		TreeView: tview.NewTreeView(),
+	}
+
+	ct.SetBorder(true)
+	ct.SetBorderPadding(cfg.BorderPadding())
+
+	return ct
+}

+ 68 - 0
config.go

@@ -0,0 +1,68 @@
+package main
+
+import (
+	"encoding/json"
+	"os"
+	"path/filepath"
+)
+
+const name = "discordo"
+
+type ThemeConfig struct {
+	BorderPadding [4]int
+}
+
+type Config struct {
+	Mouse bool
+	Theme ThemeConfig
+}
+
+func (c *Config) BorderPadding() (int, int, int, int) {
+	pad := c.Theme.BorderPadding
+	return pad[0], pad[1], pad[2], pad[3]
+}
+
+func newConfig() (*Config, error) {
+	path, err := os.UserConfigDir()
+	if err != nil {
+		return nil, err
+	}
+
+	path = filepath.Join(path, name)
+	if err = os.MkdirAll(path, os.ModePerm); err != nil {
+		return nil, err
+	}
+
+	c := Config{
+		Mouse: true,
+		Theme: ThemeConfig{
+			BorderPadding: [...]int{1, 1, 1, 1},
+		},
+	}
+	path = filepath.Join(path, "config.json")
+	if _, err = os.Stat(path); os.IsNotExist(err) {
+		f, err := os.Create(path)
+		if err != nil {
+			return nil, err
+		}
+		defer f.Close()
+
+		e := json.NewEncoder(f)
+		e.SetIndent("", "\t")
+		if err = e.Encode(c); err != nil {
+			return nil, err
+		}
+	} else {
+		f, err := os.Open(path)
+		if err != nil {
+			return nil, err
+		}
+		defer f.Close()
+
+		if err = json.NewDecoder(f).Decode(&c); err != nil {
+			return nil, err
+		}
+	}
+
+	return &c, nil
+}

+ 23 - 0
go.mod

@@ -0,0 +1,23 @@
+module github.com/ayn2op/discordo
+
+go 1.19
+
+require (
+	github.com/diamondburned/arikawa/v3 v3.1.0
+	github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c
+)
+
+require (
+	github.com/gdamore/encoding v1.0.0 // indirect
+	github.com/gdamore/tcell/v2 v2.5.3 // indirect
+	github.com/gorilla/schema v1.2.0 // indirect
+	github.com/gorilla/websocket v1.4.2 // indirect
+	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+	github.com/mattn/go-runewidth v0.0.13 // indirect
+	github.com/pkg/errors v0.9.1 // indirect
+	github.com/rivo/uniseg v0.4.2 // indirect
+	golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 // indirect
+	golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
+	golang.org/x/text v0.3.7 // indirect
+	golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
+)

+ 39 - 0
go.sum

@@ -0,0 +1,39 @@
+github.com/diamondburned/arikawa/v3 v3.1.0 h1:M7ZyjoCM4o1+rzai2NMXjOSukSrPdP6OxV68WKvKZ6E=
+github.com/diamondburned/arikawa/v3 v3.1.0/go.mod h1:5jBSNnp82Z/EhsKa6Wk9FsOqSxfVkNZDTDBPOj47LpY=
+github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
+github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
+github.com/gdamore/tcell/v2 v2.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV0=
+github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo=
+github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
+github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
+github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c h1:Y4GSXEYKYAtguH10lmQmYb7hRkJ7U+m8GvnFHKU2jrk=
+github.com/rivo/tview v0.0.0-20221221172820-02e38ea9604c/go.mod h1:lBUy/T5kyMudFzWUH/C2moN+NlU5qF505vzOyINXuUQ=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
+github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211001092434-39dca1131b70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 h1:saXMvIOKvRFwbOMicHXr0B1uwoxq9dGmLe5ExMES6c4=
+golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

+ 45 - 0
guilds_tree.go

@@ -0,0 +1,45 @@
+package main
+
+import (
+	"github.com/diamondburned/arikawa/v3/discord"
+	"github.com/rivo/tview"
+)
+
+type GuildsTree struct {
+	*tview.TreeView
+}
+
+func newGuildsTree() *GuildsTree {
+	gt := &GuildsTree{
+		TreeView: tview.NewTreeView(),
+	}
+
+	root := tview.NewTreeNode("")
+	gt.SetRoot(root)
+	gt.SetTopLevel(1)
+	gt.SetSelectedFunc(gt.onSelected)
+
+	gt.SetBorder(true)
+	gt.SetBorderPadding(cfg.BorderPadding())
+
+	return gt
+}
+
+func (gt *GuildsTree) newGuild(n *tview.TreeNode, gid discord.GuildID) error {
+	g, err := discordState.Cabinet.Guild(gid)
+	if err != nil {
+		return err
+	}
+
+	gn := tview.NewTreeNode(g.Name)
+	gn.SetReference(g.ID)
+	n.AddChild(gn)
+	return nil
+}
+
+func (gt *GuildsTree) onSelected(n *tview.TreeNode) {
+	ref := n.GetReference()
+	if ref == nil {
+
+	}
+}

+ 70 - 0
main.go

@@ -0,0 +1,70 @@
+package main
+
+import (
+	"context"
+	"flag"
+	"log"
+
+	"github.com/rivo/tview"
+)
+
+var (
+	token string
+
+	cfg          *Config
+	discordState *State
+
+	app          *tview.Application
+	flex         *tview.Flex
+	guildsTree   *GuildsTree
+	channelsTree *ChannelsTree
+	messagesText *MessagesText
+	messageInput *MessageInput
+)
+
+func init() {
+	flag.StringVar(&token, "token", "", "The authentication token.")
+}
+
+func main() {
+	flag.Parse()
+
+	var err error
+	cfg, err = newConfig()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Initialize UI
+	app = tview.NewApplication()
+
+	guildsTree = newGuildsTree()
+	channelsTree = newChannelsTree()
+	messagesText = newMessagesText()
+	messageInput = newMessageInput()
+
+	discordState = newState(token)
+	if err = discordState.Open(context.Background()); err != nil {
+		log.Fatal(err)
+	}
+
+	left := tview.NewFlex()
+	left.SetDirection(tview.FlexRow)
+	left.AddItem(guildsTree, 0, 1, true)
+	left.AddItem(channelsTree, 0, 1, false)
+
+	right := tview.NewFlex()
+	right.SetDirection(tview.FlexRow)
+	right.AddItem(messagesText, 0, 1, false)
+	right.AddItem(messageInput, 3, 1, false)
+
+	flex = tview.NewFlex()
+	flex.AddItem(left, 0, 1, false)
+	flex.AddItem(right, 0, 4, false)
+
+	app.EnableMouse(cfg.Mouse)
+	app.SetRoot(flex, true)
+	if err = app.Run(); err != nil {
+		log.Fatal(err)
+	}
+}

+ 18 - 0
message_input.go

@@ -0,0 +1,18 @@
+package main
+
+import "github.com/rivo/tview"
+
+type MessageInput struct {
+	*tview.InputField
+}
+
+func newMessageInput() *MessageInput {
+	mi := &MessageInput{
+		InputField: tview.NewInputField(),
+	}
+
+	mi.SetBorder(true)
+	mi.SetBorderPadding(cfg.BorderPadding())
+
+	return mi
+}

+ 23 - 0
messages_text.go

@@ -0,0 +1,23 @@
+package main
+
+import (
+	"github.com/rivo/tview"
+)
+
+type MessagesText struct {
+	*tview.TextView
+}
+
+func newMessagesText() *MessagesText {
+	mt := &MessagesText{
+		TextView: tview.NewTextView(),
+	}
+
+	mt.SetDynamicColors(true)
+	mt.SetRegions(true)
+
+	mt.SetBorder(true)
+	mt.SetBorderPadding(cfg.BorderPadding())
+
+	return mt
+}

+ 53 - 0
state.go

@@ -0,0 +1,53 @@
+package main
+
+import (
+	"log"
+
+	"github.com/diamondburned/arikawa/v3/gateway"
+	"github.com/diamondburned/arikawa/v3/state"
+	"github.com/rivo/tview"
+)
+
+type State struct {
+	*state.State
+}
+
+func newState(token string) *State {
+	s := &State{
+		State: state.New(token),
+	}
+
+	s.AddHandler(s.onReady)
+
+	return s
+}
+
+func (s *State) onReady(r *gateway.ReadyEvent) {
+	root := guildsTree.GetRoot()
+
+	dmNode := tview.NewTreeNode("Direct Messages")
+	root.AddChild(dmNode)
+
+	for _, gf := range r.UserSettings.GuildFolders {
+		/// If the ID of the guild folder is zero, the guild folder only contains single guild.
+		if gf.ID == 0 {
+			if err := guildsTree.newGuild(root, gf.GuildIDs[0]); err != nil {
+				log.Println(err)
+				continue
+			}
+		} else {
+			gfNode := tview.NewTreeNode("Folder")
+			root.AddChild(gfNode)
+
+			for _, gid := range gf.GuildIDs {
+				if err := guildsTree.newGuild(gfNode, gid); err != nil {
+					log.Println(err)
+					continue
+				}
+			}
+		}
+	}
+
+	guildsTree.SetCurrentNode(root)
+	app.SetFocus(guildsTree)
+}