Rename configuration fields and UI widgets
This commit is contained in:
parent
8a279e056d
commit
433da8cd68
11 changed files with 262 additions and 310 deletions
154
config/config.go
154
config/config.go
|
|
@ -11,25 +11,28 @@ import (
|
|||
|
||||
const Name = "discordo"
|
||||
|
||||
type MessagesViewKeysConfig struct {
|
||||
OpenActionsView string `yaml:"open_actions_view"`
|
||||
type (
|
||||
MessagesTextKeysConfig struct {
|
||||
LaunchActions string `yaml:"launch_actions"`
|
||||
|
||||
SelectPreviousMessage string `yaml:"select_previous_message"`
|
||||
SelectNextMessage string `yaml:"select_next_message"`
|
||||
SelectFirstMessage string `yaml:"select_first_message"`
|
||||
SelectLastMessage string `yaml:"select_last_message"`
|
||||
}
|
||||
SelectPrevious string `yaml:"select_previous"`
|
||||
SelectNext string `yaml:"select_next"`
|
||||
SelectFirst string `yaml:"select_first"`
|
||||
SelectLast string `yaml:"select_last"`
|
||||
}
|
||||
|
||||
type InputViewKeysConfig struct {
|
||||
SendMessage string `yaml:"send_message"`
|
||||
OpenExternalEditor string `yaml:"open_external_editor"`
|
||||
PasteClipboard string `yaml:"paste_clipboard"`
|
||||
}
|
||||
MessageInputKeysConfig struct {
|
||||
Send string `yaml:"send"`
|
||||
Paste string `yaml:"paste"`
|
||||
|
||||
type KeysConfig struct {
|
||||
MessagesView MessagesViewKeysConfig `yaml:"messages_view"`
|
||||
InputView InputViewKeysConfig `yaml:"input_view"`
|
||||
}
|
||||
LaunchEditor string `yaml:"launch_editor"`
|
||||
}
|
||||
|
||||
KeysConfig struct {
|
||||
MessagesText MessagesTextKeysConfig `yaml:"messages_text"`
|
||||
MessageInput MessageInputKeysConfig `yaml:"message_input"`
|
||||
}
|
||||
)
|
||||
|
||||
type ThemeConfig struct {
|
||||
Background string `yaml:"background"`
|
||||
|
|
@ -48,34 +51,77 @@ type Config struct {
|
|||
Timezone string `yaml:"timezone"`
|
||||
// A textual representation of the time value formatted according to the layout defined by its value. Learn more: https://pkg.go.dev/time#Layout
|
||||
TimeFormat string `yaml:"time_format"`
|
||||
// Keybindings
|
||||
Keys KeysConfig `yaml:"keys"`
|
||||
// Theme
|
||||
|
||||
Keys KeysConfig `yaml:"keys"`
|
||||
Theme ThemeConfig `yaml:"theme"`
|
||||
}
|
||||
|
||||
func New() *Config {
|
||||
return &Config{
|
||||
func New() (*Config, error) {
|
||||
path, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the configuration directory if it does not exist already.
|
||||
path = filepath.Join(path, Name)
|
||||
err = os.MkdirAll(path, os.ModePerm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := def()
|
||||
path = filepath.Join(path, "config.yml")
|
||||
_, err = os.Stat(path)
|
||||
// If the configuration file does not exist, create a new one and write the default configuration to it.
|
||||
if os.IsNotExist(err) {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
err = yaml.NewEncoder(f).Encode(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
err = yaml.NewDecoder(f).Decode(&c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func def() Config {
|
||||
return Config{
|
||||
Mouse: true,
|
||||
MessagesLimit: 50,
|
||||
|
||||
Timestamps: false,
|
||||
Timezone: "Local",
|
||||
TimeFormat: time.Kitchen,
|
||||
Timestamps: false,
|
||||
Timezone: "Local",
|
||||
TimeFormat: time.Kitchen,
|
||||
|
||||
Keys: KeysConfig{
|
||||
MessagesView: MessagesViewKeysConfig{
|
||||
OpenActionsView: "Rune[a]",
|
||||
MessagesText: MessagesTextKeysConfig{
|
||||
LaunchActions: "Rune[a]",
|
||||
|
||||
SelectPreviousMessage: "Up",
|
||||
SelectNextMessage: "Down",
|
||||
SelectFirstMessage: "Home",
|
||||
SelectLastMessage: "End",
|
||||
SelectPrevious: "Up",
|
||||
SelectNext: "Down",
|
||||
SelectFirst: "Home",
|
||||
SelectLast: "End",
|
||||
},
|
||||
InputView: InputViewKeysConfig{
|
||||
SendMessage: "Enter",
|
||||
OpenExternalEditor: "Ctrl+E",
|
||||
PasteClipboard: "Ctrl+V",
|
||||
MessageInput: MessageInputKeysConfig{
|
||||
Send: "Enter",
|
||||
Paste: "Ctrl+V",
|
||||
|
||||
LaunchEditor: "Ctrl+E",
|
||||
},
|
||||
},
|
||||
Theme: ThemeConfig{
|
||||
|
|
@ -86,44 +132,6 @@ func New() *Config {
|
|||
}
|
||||
}
|
||||
|
||||
func (cfg *Config) Load() error {
|
||||
path := DirPath()
|
||||
// Create the configuration directory if it does not exist already.
|
||||
err := os.MkdirAll(path, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Open the configuration file with create and read-write flag.
|
||||
f, err := os.OpenFile(
|
||||
filepath.Join(path, "config.yml"),
|
||||
os.O_CREATE|os.O_RDWR,
|
||||
os.ModePerm,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the configuration file is empty (the size of the file is zero; a new configuration file was created), write the default configuration to the file.
|
||||
if fi.Size() == 0 {
|
||||
return yaml.NewEncoder(f).Encode(cfg)
|
||||
}
|
||||
|
||||
return yaml.NewDecoder(f).Decode(&cfg)
|
||||
}
|
||||
|
||||
// DirPath returns the path of the configuration directory.
|
||||
func DirPath() string {
|
||||
path, _ := os.UserConfigDir()
|
||||
return filepath.Join(path, Name)
|
||||
}
|
||||
|
||||
// LogDirPath returns the path of the log directory.
|
||||
func LogDirPath() string {
|
||||
path, _ := os.UserCacheDir()
|
||||
|
|
|
|||
4
main.go
4
main.go
|
|
@ -38,8 +38,8 @@ func init() {
|
|||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
cfg := config.New()
|
||||
if err := cfg.Load(); err != nil {
|
||||
cfg, err := config.New()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
0
out.log
Normal file
0
out.log
Normal file
|
|
@ -15,14 +15,14 @@ import (
|
|||
|
||||
var linkRegex = regexp.MustCompile("https?://.+")
|
||||
|
||||
type ActionsView struct {
|
||||
type ActionsList struct {
|
||||
*tview.List
|
||||
app *Application
|
||||
message *discord.Message
|
||||
}
|
||||
|
||||
func newActionsView(app *Application, m *discord.Message) *ActionsView {
|
||||
v := &ActionsView{
|
||||
func newActionsList(app *Application, m *discord.Message) *ActionsList {
|
||||
v := &ActionsList{
|
||||
List: tview.NewList(),
|
||||
app: app,
|
||||
message: m,
|
||||
|
|
@ -31,13 +31,13 @@ func newActionsView(app *Application, m *discord.Message) *ActionsView {
|
|||
v.ShowSecondaryText(false)
|
||||
v.SetDoneFunc(func() {
|
||||
app.SetRoot(app.view, true)
|
||||
app.SetFocus(app.view.MessagesView)
|
||||
app.SetFocus(app.view.MessagesText)
|
||||
})
|
||||
|
||||
isDM := channelIsInDMCategory(app.view.ChannelsView.selected)
|
||||
isDM := channelIsInDMCategory(app.view.ChannelsTree.selected)
|
||||
|
||||
// If the client user has the `SEND_MESSAGES` permission, add "Reply" and "Mention Reply" actions.
|
||||
if isDM || !isDM && hasPermission(app.state, app.view.ChannelsView.selected.ID, discord.PermissionSendMessages) {
|
||||
if isDM || !isDM && hasPermission(app.state, app.view.ChannelsTree.selected.ID, discord.PermissionSendMessages) {
|
||||
v.AddItem("Reply", "", 'r', v.replyAction)
|
||||
v.AddItem("Mention Reply", "", 'R', v.mentionReplyAction)
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ func newActionsView(app *Application, m *discord.Message) *ActionsView {
|
|||
}
|
||||
|
||||
app.SetRoot(app.view, true)
|
||||
app.SetFocus(app.view.MessagesView)
|
||||
app.SetFocus(app.view.MessagesText)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ func newActionsView(app *Application, m *discord.Message) *ActionsView {
|
|||
me, _ := app.state.MeStore.Me()
|
||||
|
||||
// If the client user has the `MANAGE_MESSAGES` permission, add a new action to delete the message.
|
||||
if (isDM && m.Author.ID == me.ID) || (!isDM && hasPermission(app.state, app.view.ChannelsView.selected.ID, discord.PermissionManageMessages)) {
|
||||
if (isDM && m.Author.ID == me.ID) || (!isDM && hasPermission(app.state, app.view.ChannelsTree.selected.ID, discord.PermissionManageMessages)) {
|
||||
v.AddItem("Delete", "", 'd', v.deleteAction)
|
||||
}
|
||||
|
||||
|
|
@ -85,37 +85,37 @@ func newActionsView(app *Application, m *discord.Message) *ActionsView {
|
|||
return v
|
||||
}
|
||||
|
||||
func (v *ActionsView) replyAction() {
|
||||
v.app.view.InputView.SetTitle("Replying to " + v.message.Author.Tag())
|
||||
func (al *ActionsList) replyAction() {
|
||||
al.app.view.MessageInput.SetTitle("Replying to " + al.message.Author.Tag())
|
||||
|
||||
v.app.SetRoot(v.app.view, true)
|
||||
v.app.SetFocus(v.app.view.InputView)
|
||||
al.app.SetRoot(al.app.view, true)
|
||||
al.app.SetFocus(al.app.view.MessageInput)
|
||||
}
|
||||
|
||||
func (v *ActionsView) mentionReplyAction() {
|
||||
v.app.view.InputView.SetTitle("[@] Replying to " + v.message.Author.Tag())
|
||||
func (al *ActionsList) mentionReplyAction() {
|
||||
al.app.view.MessageInput.SetTitle("[@] Replying to " + al.message.Author.Tag())
|
||||
|
||||
v.app.SetRoot(v.app.view, true)
|
||||
v.app.SetFocus(v.app.view.InputView)
|
||||
al.app.SetRoot(al.app.view, true)
|
||||
al.app.SetFocus(al.app.view.MessageInput)
|
||||
}
|
||||
|
||||
func (v *ActionsView) selectReplyAction() {
|
||||
ms, err := v.app.state.Cabinet.Messages(v.message.ChannelID)
|
||||
func (al *ActionsList) selectReplyAction() {
|
||||
ms, err := al.app.state.Cabinet.Messages(al.message.ChannelID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
v.app.view.MessagesView.selected, _ = findMessageByID(ms, v.message.ReferencedMessage.ID)
|
||||
v.app.view.MessagesView.
|
||||
Highlight(v.message.ReferencedMessage.ID.String()).
|
||||
al.app.view.MessagesText.selected, _ = findMessageByID(ms, al.message.ReferencedMessage.ID)
|
||||
al.app.view.MessagesText.
|
||||
Highlight(al.message.ReferencedMessage.ID.String()).
|
||||
ScrollToHighlight()
|
||||
|
||||
v.app.SetRoot(v.app.view, true)
|
||||
v.app.SetFocus(v.app.view.MessagesView)
|
||||
al.app.SetRoot(al.app.view, true)
|
||||
al.app.SetFocus(al.app.view.MessagesText)
|
||||
}
|
||||
|
||||
func (v *ActionsView) openAttachmentAction() {
|
||||
for _, a := range v.message.Attachments {
|
||||
func (al *ActionsList) openAttachmentAction() {
|
||||
for _, a := range al.message.Attachments {
|
||||
cacheDirPath, _ := os.UserCacheDir()
|
||||
f, err := os.Create(filepath.Join(cacheDirPath, a.Filename))
|
||||
if err != nil {
|
||||
|
|
@ -137,12 +137,12 @@ func (v *ActionsView) openAttachmentAction() {
|
|||
go open.Run(f.Name())
|
||||
}
|
||||
|
||||
v.app.SetRoot(v.app.view, true)
|
||||
v.app.SetFocus(v.app.view.MessagesView)
|
||||
al.app.SetRoot(al.app.view, true)
|
||||
al.app.SetFocus(al.app.view.MessagesText)
|
||||
}
|
||||
|
||||
func (v *ActionsView) downloadAttachmentAction() {
|
||||
for _, a := range v.message.Attachments {
|
||||
func (al *ActionsList) downloadAttachmentAction() {
|
||||
for _, a := range al.message.Attachments {
|
||||
path, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
path = os.TempDir()
|
||||
|
|
@ -168,66 +168,66 @@ func (v *ActionsView) downloadAttachmentAction() {
|
|||
f.Write(d)
|
||||
}
|
||||
|
||||
v.app.SetRoot(v.app.view, true)
|
||||
v.app.SetFocus(v.app.view.MessagesView)
|
||||
al.app.SetRoot(al.app.view, true)
|
||||
al.app.SetFocus(al.app.view.MessagesText)
|
||||
}
|
||||
|
||||
func (v *ActionsView) deleteAction() {
|
||||
v.app.view.MessagesView.Clear()
|
||||
func (al *ActionsList) deleteAction() {
|
||||
al.app.view.MessagesText.Clear()
|
||||
|
||||
err := v.app.state.MessageRemove(v.message.ChannelID, v.message.ID)
|
||||
err := al.app.state.MessageRemove(al.message.ChannelID, al.message.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = v.app.state.DeleteMessage(v.message.ChannelID, v.message.ID, "Unknown")
|
||||
err = al.app.state.DeleteMessage(al.message.ChannelID, al.message.ID, "Unknown")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// The returned slice will be sorted from latest to oldest.
|
||||
ms, err := v.app.state.Cabinet.Messages(v.message.ChannelID)
|
||||
ms, err := al.app.state.Cabinet.Messages(al.message.ChannelID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i := len(ms) - 1; i >= 0; i-- {
|
||||
_, err = v.app.view.MessagesView.Write(buildMessage(v.app, ms[i]))
|
||||
_, err = al.app.view.MessagesText.Write(buildMessage(al.app, ms[i]))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
v.app.SetRoot(v.app.view, true)
|
||||
v.app.SetFocus(v.app.view.MessagesView)
|
||||
al.app.SetRoot(al.app.view, true)
|
||||
al.app.SetFocus(al.app.view.MessagesText)
|
||||
}
|
||||
|
||||
func (v *ActionsView) copyContentAction() {
|
||||
err := clipboard.WriteAll(v.message.Content)
|
||||
func (al *ActionsList) copyContentAction() {
|
||||
err := clipboard.WriteAll(al.message.Content)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
v.app.SetRoot(v.app.view, true)
|
||||
v.app.SetFocus(v.app.view.MessagesView)
|
||||
al.app.SetRoot(al.app.view, true)
|
||||
al.app.SetFocus(al.app.view.MessagesText)
|
||||
}
|
||||
|
||||
func (v *ActionsView) copyIDAction() {
|
||||
err := clipboard.WriteAll(v.message.ID.String())
|
||||
func (al *ActionsList) copyIDAction() {
|
||||
err := clipboard.WriteAll(al.message.ID.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
v.app.SetRoot(v.app.view, true)
|
||||
v.app.SetFocus(v.app.view.MessagesView)
|
||||
al.app.SetRoot(al.app.view, true)
|
||||
al.app.SetFocus(al.app.view.MessagesText)
|
||||
}
|
||||
|
||||
func (v *ActionsView) copyLinkAction() {
|
||||
err := clipboard.WriteAll(v.message.URL())
|
||||
func (al *ActionsList) copyLinkAction() {
|
||||
err := clipboard.WriteAll(al.message.URL())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
v.app.SetRoot(v.app.view, true)
|
||||
v.app.SetFocus(v.app.view.MessagesView)
|
||||
al.app.SetRoot(al.app.view, true)
|
||||
al.app.SetFocus(al.app.view.MessagesText)
|
||||
}
|
||||
|
|
@ -73,9 +73,9 @@ func (app *Application) Run(token string) {
|
|||
}
|
||||
|
||||
app.SetRoot(app.view, true)
|
||||
app.SetFocus(app.view.GuildsView)
|
||||
app.SetFocus(app.view.GuildsTree)
|
||||
} else {
|
||||
loginView := newLoginView(app)
|
||||
loginView := newLoginForm(app)
|
||||
app.SetRoot(loginView, true)
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ func (app *Application) onBeforeDraw(screen tcell.Screen) bool {
|
|||
}
|
||||
|
||||
func (c *Application) onReady(r *gateway.ReadyEvent) {
|
||||
root := c.view.GuildsView.GetRoot()
|
||||
root := c.view.GuildsTree.GetRoot()
|
||||
for _, gf := range r.UserSettings.GuildFolders {
|
||||
if gf.ID == 0 {
|
||||
for _, gID := range gf.GuildIDs {
|
||||
|
|
@ -154,24 +154,24 @@ func (c *Application) onReady(r *gateway.ReadyEvent) {
|
|||
|
||||
}
|
||||
|
||||
c.view.GuildsView.SetCurrentNode(root)
|
||||
c.SetFocus(c.view.GuildsView)
|
||||
c.view.GuildsTree.SetCurrentNode(root)
|
||||
c.SetFocus(c.view.GuildsTree)
|
||||
}
|
||||
|
||||
func (c *Application) onGuildCreate(g *gateway.GuildCreateEvent) {
|
||||
guildNode := tview.NewTreeNode(g.Name)
|
||||
guildNode.SetReference(g.ID)
|
||||
|
||||
rootNode := c.view.GuildsView.GetRoot()
|
||||
rootNode := c.view.GuildsTree.GetRoot()
|
||||
rootNode.AddChild(guildNode)
|
||||
|
||||
c.view.GuildsView.SetCurrentNode(rootNode)
|
||||
c.SetFocus(c.view.GuildsView)
|
||||
c.view.GuildsTree.SetCurrentNode(rootNode)
|
||||
c.SetFocus(c.view.GuildsTree)
|
||||
c.Draw()
|
||||
}
|
||||
|
||||
func (c *Application) onGuildDelete(g *gateway.GuildDeleteEvent) {
|
||||
rootNode := c.view.GuildsView.GetRoot()
|
||||
rootNode := c.view.GuildsTree.GetRoot()
|
||||
var parentNode *tview.TreeNode
|
||||
rootNode.Walk(func(node, _ *tview.TreeNode) bool {
|
||||
if node.GetReference() == g.ID {
|
||||
|
|
@ -190,14 +190,14 @@ func (c *Application) onGuildDelete(g *gateway.GuildDeleteEvent) {
|
|||
}
|
||||
|
||||
func (c *Application) onMessageCreate(m *gateway.MessageCreateEvent) {
|
||||
if c.view.ChannelsView.selected != nil && m.ChannelID == c.view.ChannelsView.selected.ID {
|
||||
_, err := c.view.MessagesView.Write(buildMessage(c, m.Message))
|
||||
if c.view.ChannelsTree.selected != nil && m.ChannelID == c.view.ChannelsTree.selected.ID {
|
||||
_, err := c.view.MessagesText.Write(buildMessage(c, m.Message))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(c.view.MessagesView.GetHighlights()) == 0 {
|
||||
c.view.MessagesView.ScrollToEnd()
|
||||
if len(c.view.MessagesText.GetHighlights()) == 0 {
|
||||
c.view.MessagesText.ScrollToEnd()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
type ChannelsView struct {
|
||||
type ChannelsTree struct {
|
||||
*tview.TreeView
|
||||
|
||||
app *Application
|
||||
selected *discord.Channel
|
||||
}
|
||||
|
||||
func newChannelsView(app *Application) *ChannelsView {
|
||||
v := &ChannelsView{
|
||||
func newChannelsTree(app *Application) *ChannelsTree {
|
||||
v := &ChannelsTree{
|
||||
TreeView: tview.NewTreeView(),
|
||||
|
||||
app: app,
|
||||
|
|
@ -34,14 +34,14 @@ func newChannelsView(app *Application) *ChannelsView {
|
|||
return v
|
||||
}
|
||||
|
||||
func (v *ChannelsView) onSelected(node *tview.TreeNode) {
|
||||
func (v *ChannelsTree) onSelected(node *tview.TreeNode) {
|
||||
v.selected = nil
|
||||
v.app.view.MessagesView.selected = -1
|
||||
v.app.view.MessagesView.
|
||||
v.app.view.MessagesText.selected = -1
|
||||
v.app.view.MessagesText.
|
||||
Highlight().
|
||||
Clear().
|
||||
SetTitle("")
|
||||
v.app.view.InputView.SetText("")
|
||||
v.app.view.MessageInput.SetText("")
|
||||
|
||||
ref := node.GetReference()
|
||||
if ref == nil {
|
||||
|
|
@ -64,21 +64,21 @@ func (v *ChannelsView) onSelected(node *tview.TreeNode) {
|
|||
default:
|
||||
v.selected = c
|
||||
|
||||
v.app.view.MessagesView.setTitle(c)
|
||||
v.app.SetFocus(v.app.view.InputView)
|
||||
v.app.view.MessagesText.setTitle(c)
|
||||
v.app.SetFocus(v.app.view.MessageInput)
|
||||
|
||||
go v.app.view.MessagesView.loadMessages(c)
|
||||
go v.app.view.MessagesText.loadMessages(c)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *ChannelsView) createChannelNode(c discord.Channel) *tview.TreeNode {
|
||||
func (v *ChannelsTree) createChannelNode(c discord.Channel) *tview.TreeNode {
|
||||
channelNode := tview.NewTreeNode(channelToString(c))
|
||||
channelNode.SetReference(c.ID)
|
||||
|
||||
return channelNode
|
||||
}
|
||||
|
||||
func (v *ChannelsView) createPrivateChannelNodes(root *tview.TreeNode) {
|
||||
func (v *ChannelsTree) createPrivateChannelNodes(root *tview.TreeNode) {
|
||||
cs, err := v.app.state.Cabinet.PrivateChannels()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
|
@ -102,7 +102,7 @@ func (v *ChannelsView) createPrivateChannelNodes(root *tview.TreeNode) {
|
|||
}
|
||||
}
|
||||
|
||||
func (v *ChannelsView) createGuildChannelNodes(root *tview.TreeNode, gID discord.GuildID) {
|
||||
func (v *ChannelsTree) createGuildChannelNodes(root *tview.TreeNode, gID discord.GuildID) {
|
||||
cs, err := v.app.state.Cabinet.Channels(gID)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
|
@ -118,7 +118,7 @@ func (v *ChannelsView) createGuildChannelNodes(root *tview.TreeNode, gID discord
|
|||
v.createChildrenChannelNodes(root, cs)
|
||||
}
|
||||
|
||||
func (v *ChannelsView) createOrphanChannelNodes(root *tview.TreeNode, cs []discord.Channel) {
|
||||
func (v *ChannelsTree) createOrphanChannelNodes(root *tview.TreeNode, cs []discord.Channel) {
|
||||
for _, c := range cs {
|
||||
if (c.Type == discord.GuildText || c.Type == discord.GuildNews) && (!c.ParentID.IsValid()) {
|
||||
root.AddChild(v.createChannelNode(c))
|
||||
|
|
@ -126,7 +126,7 @@ func (v *ChannelsView) createOrphanChannelNodes(root *tview.TreeNode, cs []disco
|
|||
}
|
||||
}
|
||||
|
||||
func (v *ChannelsView) createCategoryChannelNodes(root *tview.TreeNode, cs []discord.Channel) {
|
||||
func (v *ChannelsTree) createCategoryChannelNodes(root *tview.TreeNode, cs []discord.Channel) {
|
||||
CATEGORY:
|
||||
for _, c := range cs {
|
||||
if c.Type == discord.GuildCategory {
|
||||
|
|
@ -142,7 +142,7 @@ CATEGORY:
|
|||
}
|
||||
}
|
||||
|
||||
func (v *ChannelsView) createChildrenChannelNodes(root *tview.TreeNode, cs []discord.Channel) {
|
||||
func (v *ChannelsTree) createChildrenChannelNodes(root *tview.TreeNode, cs []discord.Channel) {
|
||||
for _, c := range cs {
|
||||
if (c.Type == discord.GuildText || c.Type == discord.GuildNews) && (c.ParentID.IsValid()) {
|
||||
var parentNode *tview.TreeNode
|
||||
|
|
@ -5,14 +5,14 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
type GuildsView struct {
|
||||
type GuildsTree struct {
|
||||
*tview.TreeView
|
||||
|
||||
app *Application
|
||||
}
|
||||
|
||||
func newGuildsView(app *Application) *GuildsView {
|
||||
v := &GuildsView{
|
||||
func newGuildsTree(app *Application) *GuildsTree {
|
||||
v := &GuildsTree{
|
||||
TreeView: tview.NewTreeView(),
|
||||
|
||||
app: app,
|
||||
|
|
@ -33,16 +33,16 @@ func newGuildsView(app *Application) *GuildsView {
|
|||
return v
|
||||
}
|
||||
|
||||
func (v *GuildsView) onSelected(node *tview.TreeNode) {
|
||||
v.app.view.ChannelsView.selected = nil
|
||||
v.app.view.MessagesView.selected = -1
|
||||
rootNode := v.app.view.ChannelsView.GetRoot()
|
||||
func (v *GuildsTree) onSelected(node *tview.TreeNode) {
|
||||
v.app.view.ChannelsTree.selected = nil
|
||||
v.app.view.MessagesText.selected = -1
|
||||
rootNode := v.app.view.ChannelsTree.GetRoot()
|
||||
rootNode.ClearChildren()
|
||||
v.app.view.MessagesView.
|
||||
v.app.view.MessagesText.
|
||||
Highlight().
|
||||
Clear().
|
||||
SetTitle("")
|
||||
v.app.view.InputView.SetText("")
|
||||
v.app.view.MessageInput.SetText("")
|
||||
|
||||
// If the selected node has children (guild folder), expand the selected node if it is collapsed, otherwise collapse.
|
||||
if len(node.GetChildren()) != 0 {
|
||||
|
|
@ -53,11 +53,11 @@ func (v *GuildsView) onSelected(node *tview.TreeNode) {
|
|||
ref := node.GetReference()
|
||||
// If the reference of the selected node is nil, it must be the direct messages node.
|
||||
if ref == nil {
|
||||
v.app.view.ChannelsView.createPrivateChannelNodes(rootNode)
|
||||
v.app.view.ChannelsTree.createPrivateChannelNodes(rootNode)
|
||||
} else { // Guild
|
||||
v.app.view.ChannelsView.createGuildChannelNodes(rootNode, ref.(discord.GuildID))
|
||||
v.app.view.ChannelsTree.createGuildChannelNodes(rootNode, ref.(discord.GuildID))
|
||||
}
|
||||
|
||||
v.app.view.ChannelsView.SetCurrentNode(rootNode)
|
||||
v.app.SetFocus(v.app.view.ChannelsView)
|
||||
v.app.view.ChannelsTree.SetCurrentNode(rootNode)
|
||||
v.app.SetFocus(v.app.view.ChannelsTree)
|
||||
}
|
||||
|
|
@ -10,31 +10,31 @@ import (
|
|||
"github.com/zalando/go-keyring"
|
||||
)
|
||||
|
||||
type LoginView struct {
|
||||
type LoginForm struct {
|
||||
*tview.Form
|
||||
app *Application
|
||||
}
|
||||
|
||||
func newLoginView(app *Application) *LoginView {
|
||||
v := &LoginView{
|
||||
func newLoginForm(app *Application) *LoginForm {
|
||||
lf := &LoginForm{
|
||||
Form: tview.NewForm(),
|
||||
app: app,
|
||||
}
|
||||
|
||||
v.AddInputField("Email", "", 0, nil, nil)
|
||||
v.AddPasswordField("Password", "", 0, 0, nil)
|
||||
v.AddPasswordField("Code (optional)", "", 0, 0, nil)
|
||||
v.AddButton("Login", v.onLoginButtonSelected)
|
||||
lf.AddInputField("Email", "", 0, nil, nil)
|
||||
lf.AddPasswordField("Password", "", 0, 0, nil)
|
||||
lf.AddPasswordField("Code (optional)", "", 0, 0, nil)
|
||||
lf.AddButton("Login", lf.onLoginButtonSelected)
|
||||
|
||||
v.SetTitle("Login")
|
||||
v.SetTitleAlign(tview.AlignLeft)
|
||||
v.SetBorder(true)
|
||||
v.SetBorderPadding(1, 1, 1, 1)
|
||||
lf.SetTitle("Login")
|
||||
lf.SetTitleAlign(tview.AlignLeft)
|
||||
lf.SetBorder(true)
|
||||
lf.SetBorderPadding(1, 1, 1, 1)
|
||||
|
||||
return v
|
||||
return lf
|
||||
}
|
||||
|
||||
func (v *LoginView) onLoginButtonSelected() {
|
||||
func (v *LoginForm) onLoginButtonSelected() {
|
||||
email := v.GetFormItem(0).(*tview.InputField).GetText()
|
||||
password := v.GetFormItem(1).(*tview.InputField).GetText()
|
||||
if email == "" || password == "" {
|
||||
|
|
@ -69,7 +69,7 @@ func (v *LoginView) onLoginButtonSelected() {
|
|||
}
|
||||
|
||||
v.app.SetRoot(v.app.view, true)
|
||||
v.app.SetFocus(v.app.view.GuildsView)
|
||||
v.app.SetFocus(v.app.view.GuildsTree)
|
||||
|
||||
go keyring.Set(config.Name, "token", l.Token)
|
||||
}
|
||||
|
|
@ -15,53 +15,53 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
type InputView struct {
|
||||
type MessageInput struct {
|
||||
*tview.InputField
|
||||
|
||||
app *Application
|
||||
}
|
||||
|
||||
func newInputView(app *Application) *InputView {
|
||||
v := &InputView{
|
||||
func newMessageInput(app *Application) *MessageInput {
|
||||
mi := &MessageInput{
|
||||
InputField: tview.NewInputField(),
|
||||
|
||||
app: app,
|
||||
}
|
||||
|
||||
v.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor)
|
||||
v.SetPlaceholder("Message...")
|
||||
v.SetPlaceholderStyle(tcell.StyleDefault.Background(tview.Styles.PrimitiveBackgroundColor))
|
||||
v.SetInputCapture(v.inputCapture)
|
||||
mi.SetFieldBackgroundColor(tview.Styles.PrimitiveBackgroundColor)
|
||||
mi.SetPlaceholder("Message...")
|
||||
mi.SetPlaceholderStyle(tcell.StyleDefault.Background(tview.Styles.PrimitiveBackgroundColor))
|
||||
mi.SetInputCapture(mi.inputCapture)
|
||||
|
||||
v.SetTitleAlign(tview.AlignLeft)
|
||||
v.SetBorder(true)
|
||||
v.SetBorderPadding(0, 0, 1, 1)
|
||||
mi.SetTitleAlign(tview.AlignLeft)
|
||||
mi.SetBorder(true)
|
||||
mi.SetBorderPadding(0, 0, 1, 1)
|
||||
|
||||
return v
|
||||
return mi
|
||||
}
|
||||
|
||||
func (v *InputView) inputCapture(event *tcell.EventKey) *tcell.EventKey {
|
||||
func (v *MessageInput) inputCapture(event *tcell.EventKey) *tcell.EventKey {
|
||||
switch event.Name() {
|
||||
case v.app.config.Keys.InputView.SendMessage:
|
||||
case v.app.config.Keys.MessageInput.Send:
|
||||
return v.sendMessage()
|
||||
case v.app.config.Keys.InputView.OpenExternalEditor:
|
||||
case v.app.config.Keys.MessageInput.LaunchEditor:
|
||||
return v.openExternalEditor()
|
||||
case v.app.config.Keys.InputView.PasteClipboard:
|
||||
case v.app.config.Keys.MessageInput.Paste:
|
||||
return v.pasteClipboard()
|
||||
case "Esc":
|
||||
v.
|
||||
SetText("").
|
||||
SetTitle("")
|
||||
v.app.view.MessagesView.selected = -1
|
||||
v.app.view.MessagesView.Highlight()
|
||||
v.app.view.MessagesText.selected = -1
|
||||
v.app.view.MessagesText.Highlight()
|
||||
return nil
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
func (v *InputView) sendMessage() *tcell.EventKey {
|
||||
if v.app.view.ChannelsView.selected == nil {
|
||||
func (v *MessageInput) sendMessage() *tcell.EventKey {
|
||||
if v.app.view.ChannelsTree.selected == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -70,14 +70,14 @@ func (v *InputView) sendMessage() *tcell.EventKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
ms, err := v.app.state.Messages(v.app.view.ChannelsView.selected.ID, v.app.config.MessagesLimit)
|
||||
ms, err := v.app.state.Messages(v.app.view.ChannelsTree.selected.ID, v.app.config.MessagesLimit)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(v.app.view.MessagesView.GetHighlights()) != 0 {
|
||||
mID, err := discord.ParseSnowflake(v.app.view.MessagesView.GetHighlights()[0])
|
||||
if len(v.app.view.MessagesText.GetHighlights()) != 0 {
|
||||
mID, err := discord.ParseSnowflake(v.app.view.MessagesText.GetHighlights()[0])
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
|
|
@ -99,19 +99,19 @@ func (v *InputView) sendMessage() *tcell.EventKey {
|
|||
|
||||
go v.app.state.SendMessageComplex(m.ChannelID, d)
|
||||
|
||||
v.app.view.MessagesView.selected = -1
|
||||
v.app.view.MessagesView.Highlight()
|
||||
v.app.view.MessagesText.selected = -1
|
||||
v.app.view.MessagesText.Highlight()
|
||||
|
||||
v.SetTitle("")
|
||||
} else {
|
||||
go v.app.state.SendMessage(v.app.view.ChannelsView.selected.ID, t)
|
||||
go v.app.state.SendMessage(v.app.view.ChannelsTree.selected.ID, t)
|
||||
}
|
||||
|
||||
v.SetText("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *InputView) pasteClipboard() *tcell.EventKey {
|
||||
func (v *MessageInput) pasteClipboard() *tcell.EventKey {
|
||||
text, err := clipboard.ReadAll()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
|
@ -123,7 +123,7 @@ func (v *InputView) pasteClipboard() *tcell.EventKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *InputView) openExternalEditor() *tcell.EventKey {
|
||||
func (v *MessageInput) openExternalEditor() *tcell.EventKey {
|
||||
e := os.Getenv("EDITOR")
|
||||
if e == "" {
|
||||
log.Println("environment variable EDITOR is empty")
|
||||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
type MessagesView struct {
|
||||
type MessagesText struct {
|
||||
*tview.TextView
|
||||
|
||||
// The index of the currently selected message. A negative index indicates that there is no currently selected message.
|
||||
|
|
@ -17,31 +17,31 @@ type MessagesView struct {
|
|||
app *Application
|
||||
}
|
||||
|
||||
func newMessagesView(app *Application) *MessagesView {
|
||||
v := &MessagesView{
|
||||
func newMessagesText(app *Application) *MessagesText {
|
||||
mt := &MessagesText{
|
||||
TextView: tview.NewTextView(),
|
||||
|
||||
selected: -1,
|
||||
app: app,
|
||||
}
|
||||
|
||||
v.SetDynamicColors(true)
|
||||
v.SetRegions(true)
|
||||
v.SetWordWrap(true)
|
||||
v.SetInputCapture(v.onInputCapture)
|
||||
v.SetChangedFunc(func() {
|
||||
v.app.Draw()
|
||||
mt.SetDynamicColors(true)
|
||||
mt.SetRegions(true)
|
||||
mt.SetWordWrap(true)
|
||||
mt.SetInputCapture(mt.onInputCapture)
|
||||
mt.SetChangedFunc(func() {
|
||||
mt.app.Draw()
|
||||
})
|
||||
|
||||
v.SetTitle("Messages")
|
||||
v.SetTitleAlign(tview.AlignLeft)
|
||||
v.SetBorder(true)
|
||||
v.SetBorderPadding(0, 0, 1, 1)
|
||||
mt.SetTitle("Messages")
|
||||
mt.SetTitleAlign(tview.AlignLeft)
|
||||
mt.SetBorder(true)
|
||||
mt.SetBorderPadding(0, 0, 1, 1)
|
||||
|
||||
return v
|
||||
return mt
|
||||
}
|
||||
|
||||
func (v *MessagesView) setTitle(c *discord.Channel) {
|
||||
func (v *MessagesText) setTitle(c *discord.Channel) {
|
||||
title := channelToString(*c)
|
||||
if c.Topic != "" {
|
||||
title += " - " + discordmd.Parse(c.Topic)
|
||||
|
|
@ -50,7 +50,7 @@ func (v *MessagesView) setTitle(c *discord.Channel) {
|
|||
v.SetTitle(title)
|
||||
}
|
||||
|
||||
func (v *MessagesView) loadMessages(c *discord.Channel) {
|
||||
func (v *MessagesText) loadMessages(c *discord.Channel) {
|
||||
// The returned slice will be sorted from latest to oldest.
|
||||
ms, err := v.app.state.Messages(c.ID, v.app.config.MessagesLimit)
|
||||
if err != nil {
|
||||
|
|
@ -59,7 +59,7 @@ func (v *MessagesView) loadMessages(c *discord.Channel) {
|
|||
}
|
||||
|
||||
for i := len(ms) - 1; i >= 0; i-- {
|
||||
_, err = v.app.view.MessagesView.Write(buildMessage(v.app, ms[i]))
|
||||
_, err = v.app.view.MessagesText.Write(buildMessage(v.app, ms[i]))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
|
|
@ -69,32 +69,32 @@ func (v *MessagesView) loadMessages(c *discord.Channel) {
|
|||
v.ScrollToEnd()
|
||||
}
|
||||
|
||||
func (v *MessagesView) onInputCapture(e *tcell.EventKey) *tcell.EventKey {
|
||||
if v.app.view.ChannelsView.selected == nil {
|
||||
func (v *MessagesText) onInputCapture(e *tcell.EventKey) *tcell.EventKey {
|
||||
if v.app.view.ChannelsTree.selected == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Messages should return messages ordered from latest to earliest.
|
||||
ms, err := v.app.state.Cabinet.Messages(v.app.view.ChannelsView.selected.ID)
|
||||
ms, err := v.app.state.Cabinet.Messages(v.app.view.ChannelsTree.selected.ID)
|
||||
if err != nil || len(ms) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch e.Name() {
|
||||
case v.app.config.Keys.MessagesView.OpenActionsView:
|
||||
case v.app.config.Keys.MessagesText.LaunchActions:
|
||||
return v.openActionsView(ms)
|
||||
|
||||
case v.app.config.Keys.MessagesView.SelectPreviousMessage:
|
||||
case v.app.config.Keys.MessagesText.SelectPrevious:
|
||||
return v.selectPreviousMessage(ms)
|
||||
case v.app.config.Keys.MessagesView.SelectNextMessage:
|
||||
case v.app.config.Keys.MessagesText.SelectNext:
|
||||
return v.selectNextMessage(ms)
|
||||
case v.app.config.Keys.MessagesView.SelectFirstMessage:
|
||||
case v.app.config.Keys.MessagesText.SelectFirst:
|
||||
return v.selectFirstMessage(ms)
|
||||
case v.app.config.Keys.MessagesView.SelectLastMessage:
|
||||
case v.app.config.Keys.MessagesText.SelectLast:
|
||||
return v.selectLastMessage(ms)
|
||||
case "Esc":
|
||||
v.selected = -1
|
||||
v.app.view.ChannelsView.selected = nil
|
||||
v.app.view.ChannelsTree.selected = nil
|
||||
|
||||
v.app.SetFocus(v.app.view)
|
||||
v.
|
||||
|
|
@ -107,7 +107,7 @@ func (v *MessagesView) onInputCapture(e *tcell.EventKey) *tcell.EventKey {
|
|||
return e
|
||||
}
|
||||
|
||||
func (v *MessagesView) selectPreviousMessage(ms []discord.Message) *tcell.EventKey {
|
||||
func (v *MessagesText) selectPreviousMessage(ms []discord.Message) *tcell.EventKey {
|
||||
// If there are no highlighted regions, select the latest (last) message.
|
||||
if len(v.GetHighlights()) == 0 {
|
||||
v.selected = 0
|
||||
|
|
@ -125,7 +125,7 @@ func (v *MessagesView) selectPreviousMessage(ms []discord.Message) *tcell.EventK
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *MessagesView) selectNextMessage(ms []discord.Message) *tcell.EventKey {
|
||||
func (v *MessagesText) selectNextMessage(ms []discord.Message) *tcell.EventKey {
|
||||
// If there are no highlighted regions, select the latest (last) message.
|
||||
if len(v.GetHighlights()) == 0 {
|
||||
v.selected = 0
|
||||
|
|
@ -144,7 +144,7 @@ func (v *MessagesView) selectNextMessage(ms []discord.Message) *tcell.EventKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *MessagesView) selectFirstMessage(ms []discord.Message) *tcell.EventKey {
|
||||
func (v *MessagesText) selectFirstMessage(ms []discord.Message) *tcell.EventKey {
|
||||
v.selected = len(ms) - 1
|
||||
v.
|
||||
Highlight(ms[v.selected].ID.String()).
|
||||
|
|
@ -152,7 +152,7 @@ func (v *MessagesView) selectFirstMessage(ms []discord.Message) *tcell.EventKey
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *MessagesView) selectLastMessage(ms []discord.Message) *tcell.EventKey {
|
||||
func (v *MessagesText) selectLastMessage(ms []discord.Message) *tcell.EventKey {
|
||||
v.selected = 0
|
||||
v.
|
||||
Highlight(ms[v.selected].ID.String()).
|
||||
|
|
@ -160,7 +160,7 @@ func (v *MessagesView) selectLastMessage(ms []discord.Message) *tcell.EventKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *MessagesView) openActionsView(ms []discord.Message) *tcell.EventKey {
|
||||
func (v *MessagesText) openActionsView(ms []discord.Message) *tcell.EventKey {
|
||||
hs := v.GetHighlights()
|
||||
if len(hs) == 0 {
|
||||
return nil
|
||||
|
|
@ -176,7 +176,7 @@ func (v *MessagesView) openActionsView(ms []discord.Message) *tcell.EventKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
actionsView := newActionsView(v.app, m)
|
||||
actionsView := newActionsList(v.app, m)
|
||||
v.app.SetRoot(actionsView, true)
|
||||
return nil
|
||||
}
|
||||
82
ui/view.go
82
ui/view.go
|
|
@ -1,98 +1,42 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
type focusedId int
|
||||
|
||||
const (
|
||||
focusedIdGuildsView focusedId = iota
|
||||
focusedIdChannelsView
|
||||
focusedIdMessagesView
|
||||
focusedIdInputView
|
||||
)
|
||||
|
||||
type View struct {
|
||||
*tview.Flex
|
||||
|
||||
GuildsView *GuildsView
|
||||
ChannelsView *ChannelsView
|
||||
MessagesView *MessagesView
|
||||
InputView *InputView
|
||||
GuildsTree *GuildsTree
|
||||
ChannelsTree *ChannelsTree
|
||||
MessagesText *MessagesText
|
||||
MessageInput *MessageInput
|
||||
|
||||
app *Application
|
||||
focused focusedId
|
||||
app *Application
|
||||
}
|
||||
|
||||
func newView(app *Application) *View {
|
||||
v := &View{
|
||||
Flex: tview.NewFlex(),
|
||||
GuildsView: newGuildsView(app),
|
||||
ChannelsView: newChannelsView(app),
|
||||
MessagesView: newMessagesView(app),
|
||||
InputView: newInputView(app),
|
||||
GuildsTree: newGuildsTree(app),
|
||||
ChannelsTree: newChannelsTree(app),
|
||||
MessagesText: newMessagesText(app),
|
||||
MessageInput: newMessageInput(app),
|
||||
|
||||
app: app,
|
||||
}
|
||||
|
||||
left := tview.NewFlex().
|
||||
SetDirection(tview.FlexRow).
|
||||
AddItem(v.GuildsView, 10, 1, false).
|
||||
AddItem(v.ChannelsView, 0, 1, false)
|
||||
AddItem(v.GuildsTree, 10, 1, false).
|
||||
AddItem(v.ChannelsTree, 0, 1, false)
|
||||
right := tview.NewFlex().
|
||||
SetDirection(tview.FlexRow).
|
||||
AddItem(v.MessagesView, 0, 1, false).
|
||||
AddItem(v.InputView, 3, 1, false)
|
||||
AddItem(v.MessagesText, 0, 1, false).
|
||||
AddItem(v.MessageInput, 3, 1, false)
|
||||
|
||||
v.AddItem(left, 0, 1, false)
|
||||
v.AddItem(right, 0, 4, false)
|
||||
|
||||
v.SetInputCapture(v.onInputCapture)
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *View) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
|
||||
switch event.Key() {
|
||||
case tcell.KeyEsc:
|
||||
v.focused = 0
|
||||
case tcell.KeyBacktab:
|
||||
// If the currently focused view is the guilds view (first), then focus the input view (last)
|
||||
if v.focused == 0 {
|
||||
v.focused = focusedIdInputView
|
||||
} else {
|
||||
v.focused--
|
||||
}
|
||||
|
||||
v.setFocus()
|
||||
case tcell.KeyTab:
|
||||
// If the currently focused view is the input view (last), then focus the guilds view (first)
|
||||
if v.focused == focusedIdInputView {
|
||||
v.focused = focusedIdGuildsView
|
||||
} else {
|
||||
v.focused++
|
||||
}
|
||||
|
||||
v.setFocus()
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
func (v *View) setFocus() {
|
||||
var p tview.Primitive
|
||||
switch v.focused {
|
||||
case focusedIdGuildsView:
|
||||
p = v.GuildsView
|
||||
case focusedIdChannelsView:
|
||||
p = v.ChannelsView
|
||||
case focusedIdMessagesView:
|
||||
p = v.MessagesView
|
||||
case focusedIdInputView:
|
||||
p = v.InputView
|
||||
}
|
||||
|
||||
v.app.SetFocus(p)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue