feat: floating url list (#520)

This commit is contained in:
Ayyan 2025-03-25 23:20:03 -04:00 • committed by GitHub
parent 418a25ddff
commit a2be9c3329
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 65 additions and 65 deletions

View file

@ -16,6 +16,7 @@ type App struct {
cfg *config.Config
pages *tview.Pages
flex *tview.Flex
guildsTree *GuildsTree
messagesText *MessagesText
@ -29,6 +30,7 @@ func newApp(cfg *config.Config) *App {
cfg: cfg,
pages: tview.NewPages(),
flex: tview.NewFlex(),
guildsTree: newGuildsTree(app, cfg),
messagesText: newMessagesText(app, cfg),
@ -57,7 +59,7 @@ func (app *App) show(token string) error {
}
app.init()
app.SetRoot(app.flex, true)
app.SetRoot(app.pages, true)
}
return nil
@ -71,16 +73,24 @@ func (app *App) run(token string) error {
return app.Run()
}
func (app *App) init() {
app.flex.Clear()
func (a *App) clearPages() {
for _, name := range a.pages.GetPageNames(false) {
a.pages.RemovePage(name)
}
}
func (a *App) init() {
a.clearPages()
a.flex.Clear()
right := tview.NewFlex()
right.SetDirection(tview.FlexRow)
right.AddItem(app.messagesText, 0, 1, false)
right.AddItem(app.messageInput, 3, 1, false)
right.AddItem(a.messagesText, 0, 1, false)
right.AddItem(a.messageInput, 3, 1, false)
// The guilds tree is always focused first at start-up.
app.flex.AddItem(app.guildsTree, 0, 1, true)
app.flex.AddItem(right, 0, 4, false)
a.flex.AddItem(a.guildsTree, 0, 1, true)
a.flex.AddItem(right, 0, 4, false)
a.pages.AddAndSwitchToPage("flex", a.flex, true)
}
func (app *App) onInputCapture(event *tcell.EventKey) *tcell.EventKey {

View file

@ -12,6 +12,7 @@ import (
"github.com/atotto/clipboard"
"github.com/ayn2op/discordo/internal/config"
"github.com/ayn2op/discordo/internal/markdown"
"github.com/ayn2op/discordo/internal/ui"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/ningen/v3/discordmd"
"github.com/gdamore/tcell/v2"
@ -330,10 +331,9 @@ func (mt *MessagesText) open() {
} else {
go openURL(msg.Attachments[0].URL)
}
return
} else {
mt.showUrlSelector(urls, msg.Attachments)
}
showSelector(mt, urls, msg.Attachments)
}
func extractURLs(content string) []string {
@ -359,17 +359,43 @@ func extractURLs(content string) []string {
return urls
}
func showSelector(mt *MessagesText, urls []string, attachments []discord.Attachment) {
func (mt *MessagesText) showUrlSelector(urls []string, attachments []discord.Attachment) {
done := func() {
app.pages.RemovePage("list").SwitchToPage("flex")
app.SetFocus(app.messagesText)
}
list := tview.NewList().
SetWrapAround(true).
SetHighlightFullLine(true).
ShowSecondaryText(false)
ShowSecondaryText(false).
SetDoneFunc(done)
p := mt.cfg.Theme.BorderPadding
list.
SetBorder(mt.cfg.Theme.Border).
SetBorderColor(tcell.GetColor(mt.cfg.Theme.BorderColor)).
SetBorderPadding(p[0], p[1], p[2], p[3]).
SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Name() {
case mt.cfg.Keys.MessagesText.SelectPrevious:
return tcell.NewEventKey(tcell.KeyUp, 0, tcell.ModNone)
case mt.cfg.Keys.MessagesText.SelectNext:
return tcell.NewEventKey(tcell.KeyDown, 0, tcell.ModNone)
case mt.cfg.Keys.MessagesText.SelectFirst:
return tcell.NewEventKey(tcell.KeyHome, 0, tcell.ModNone)
case mt.cfg.Keys.MessagesText.SelectLast:
return tcell.NewEventKey(tcell.KeyEnd, 0, tcell.ModNone)
}
return event
})
for i, a := range attachments {
attachment := a
list.AddItem(a.Filename, "", rune('a'+i), func() {
go openURL(attachment.URL)
app.SetRoot(app.flex, true)
done()
})
}
@ -377,53 +403,13 @@ func showSelector(mt *MessagesText, urls []string, attachments []discord.Attachm
urlCopy := url
list.AddItem(url, "", rune('1'+i), func() {
go openURL(urlCopy)
app.SetRoot(app.flex, true)
done()
})
}
list.AddItem("Cancel", "", 'q', func() {
app.SetRoot(app.flex, true)
})
list.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Name() {
case mt.cfg.Keys.MessagesText.SelectPrevious:
return tcell.NewEventKey(tcell.KeyUp, 0, tcell.ModNone)
case mt.cfg.Keys.MessagesText.SelectNext:
return tcell.NewEventKey(tcell.KeyDown, 0, tcell.ModNone)
case mt.cfg.Keys.MessagesText.SelectFirst:
list.SetCurrentItem(0)
return nil
case mt.cfg.Keys.MessagesText.SelectLast:
list.SetCurrentItem(list.GetItemCount() - 1)
return nil
case "Escape":
app.SetRoot(app.flex, true)
return nil
}
return event
})
height := len(urls) + len(attachments) + 1
maxHeight := 20
if height > maxHeight {
height = maxHeight
}
modal := createCenteredModal(list, height, 60)
app.SetRoot(modal, true)
app.SetFocus(list)
}
func createCenteredModal(p tview.Primitive, height, width int) tview.Primitive {
return tview.NewFlex().
AddItem(nil, 0, 1, false).
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(nil, 0, 1, false).
AddItem(p, height, 1, true).
AddItem(nil, 0, 1, false), width, 1, true).
AddItem(nil, 0, 1, false)
app.pages.
AddAndSwitchToPage("list", ui.Centered(list, 0, 0), true).
ShowPage("flex")
}
func openURL(url string) {

View file

@ -7,6 +7,7 @@ import (
"github.com/ayn2op/discordo/internal/config"
"github.com/ayn2op/discordo/internal/consts"
"github.com/ayn2op/discordo/internal/ui"
"github.com/diamondburned/arikawa/v3/api"
"github.com/diamondburned/arikawa/v3/utils/httputil"
"github.com/rivo/tview"
@ -105,13 +106,6 @@ func (f *Form) onError(err error) {
f.RemovePage("modal").SwitchToPage("form")
})
f.
AddAndSwitchToPage("modal", centered(modal, 0, 0), true).
AddAndSwitchToPage("modal", ui.Centered(modal, 0, 0), true).
ShowPage("form")
}
func centered(p tview.Primitive, width, height int) tview.Primitive {
return tview.NewGrid().
SetColumns(0, width, 0).
SetRows(0, height, 0).
AddItem(p, 1, 1, 1, 1, 0, 0, true)
}

10
internal/ui/util.go Normal file
View file

@ -0,0 +1,10 @@
package ui
import "github.com/rivo/tview"
func Centered(p tview.Primitive, width, height int) tview.Primitive {
return tview.NewGrid().
SetColumns(0, width, 0).
SetRows(0, height, 0).
AddItem(p, 1, 1, 1, 1, 0, 0, true)
}