refactor(ui/chat): migrate picker callbacks to event-based architecture (#769)
This commit is contained in:
parent
3656acba48
commit
3f8a6533da
5 changed files with 93 additions and 69 deletions
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/ayn2op/tview"
|
||||
"github.com/ayn2op/tview/help"
|
||||
"github.com/ayn2op/tview/keybind"
|
||||
"github.com/gdamore/tcell/v3"
|
||||
)
|
||||
|
||||
type attachmentItem struct {
|
||||
|
|
@ -39,8 +40,6 @@ func newAttachmentsPicker(cfg *config.Config, chatView *Model) *attachmentsPicke
|
|||
SetFooterStyle(cfg.Theme.Footer.ActiveStyle.Style)
|
||||
|
||||
ap.SetTitle("Attachments")
|
||||
ap.SetSelectedFunc(ap.onSelected)
|
||||
ap.SetCancelFunc(ap.close)
|
||||
ap.SetKeyMap(&picker.KeyMap{
|
||||
Cancel: cfg.Keybinds.Picker.Cancel.Keybind,
|
||||
Up: cfg.Keybinds.Picker.Up.Keybind,
|
||||
|
|
@ -70,23 +69,32 @@ func (ap *attachmentsPicker) SetItems(items []attachmentItem) {
|
|||
ap.Update()
|
||||
}
|
||||
|
||||
func (ap *attachmentsPicker) onSelected(item picker.Item) {
|
||||
index, ok := item.Reference.(int)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if index < 0 || index >= len(ap.items) {
|
||||
return
|
||||
}
|
||||
ap.items[index].open()
|
||||
ap.close()
|
||||
}
|
||||
|
||||
func (ap *attachmentsPicker) close() {
|
||||
ap.chatView.RemoveLayer(attachmentsListLayerName)
|
||||
ap.chatView.app.SetFocus(ap.chatView.messagesList)
|
||||
}
|
||||
|
||||
func (ap *attachmentsPicker) HandleEvent(event tcell.Event) tview.Command {
|
||||
switch event := event.(type) {
|
||||
case *picker.SelectedEvent:
|
||||
index, ok := event.Reference.(int)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if index < 0 || index >= len(ap.items) {
|
||||
return nil
|
||||
}
|
||||
ap.items[index].open()
|
||||
ap.close()
|
||||
return nil
|
||||
case *picker.CancelEvent:
|
||||
ap.close()
|
||||
return nil
|
||||
}
|
||||
|
||||
return ap.Picker.HandleEvent(event)
|
||||
}
|
||||
|
||||
func (ap *attachmentsPicker) ShortHelp() []keybind.Keybind {
|
||||
cfg := ap.cfg.Keybinds.Picker
|
||||
return []keybind.Keybind{cfg.Up.Keybind, cfg.Down.Keybind, cfg.Select.Keybind, cfg.Cancel.Keybind}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/ayn2op/tview/help"
|
||||
"github.com/ayn2op/tview/keybind"
|
||||
"github.com/diamondburned/arikawa/v3/discord"
|
||||
"github.com/gdamore/tcell/v3"
|
||||
)
|
||||
|
||||
type channelsPicker struct {
|
||||
|
|
@ -34,7 +35,6 @@ func newChannelsPicker(cfg *config.Config, chatView *Model) *channelsPicker {
|
|||
SetTitleStyle(cfg.Theme.Title.ActiveStyle.Style).
|
||||
SetFooterStyle(cfg.Theme.Footer.ActiveStyle.Style)
|
||||
|
||||
cp.SetSelectedFunc(cp.onSelected)
|
||||
cp.SetTitle("Channels")
|
||||
cp.SetScrollBarVisibility(cfg.Theme.ScrollBar.Visibility.ScrollBarVisibility)
|
||||
cp.SetScrollBar(tview.NewScrollBar().
|
||||
|
|
@ -52,31 +52,39 @@ func newChannelsPicker(cfg *config.Config, chatView *Model) *channelsPicker {
|
|||
return cp
|
||||
}
|
||||
|
||||
func (cp *channelsPicker) onSelected(item picker.Item) {
|
||||
channelID, ok := item.Reference.(discord.ChannelID)
|
||||
if !ok || !channelID.IsValid() {
|
||||
return
|
||||
}
|
||||
func (cp *channelsPicker) HandleEvent(event tcell.Event) tview.Command {
|
||||
switch event := event.(type) {
|
||||
case *picker.SelectedEvent:
|
||||
channelID, ok := event.Reference.(discord.ChannelID)
|
||||
if !ok || !channelID.IsValid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
channel, err := cp.chatView.state.Cabinet.Channel(channelID)
|
||||
if err != nil {
|
||||
slog.Error("failed to get channel from state", "err", err, "channel_id", channelID)
|
||||
return
|
||||
}
|
||||
channel, err := cp.chatView.state.Cabinet.Channel(channelID)
|
||||
if err != nil {
|
||||
slog.Error("failed to get channel from state", "err", err, "channel_id", channelID)
|
||||
return nil
|
||||
}
|
||||
|
||||
node := cp.chatView.guildsTree.findNodeByChannelID(channel.ID)
|
||||
if node == nil {
|
||||
slog.Error("failed to locate channel in tree", "channel_id", channel.ID)
|
||||
return
|
||||
}
|
||||
node := cp.chatView.guildsTree.findNodeByChannelID(channel.ID)
|
||||
if node == nil {
|
||||
slog.Error("failed to locate channel in tree", "channel_id", channel.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
cp.chatView.guildsTree.expandPathToNode(node)
|
||||
cp.chatView.guildsTree.SetCurrentNode(node)
|
||||
if channel.Type != discord.GuildCategory {
|
||||
cp.chatView.guildsTree.onSelected(node)
|
||||
cp.chatView.guildsTree.expandPathToNode(node)
|
||||
cp.chatView.guildsTree.SetCurrentNode(node)
|
||||
if channel.Type != discord.GuildCategory {
|
||||
cp.chatView.guildsTree.onSelected(node)
|
||||
}
|
||||
cp.chatView.closePicker()
|
||||
cp.chatView.focusMessageInput()
|
||||
return nil
|
||||
case *picker.CancelEvent:
|
||||
cp.chatView.closePicker()
|
||||
return nil
|
||||
}
|
||||
cp.chatView.closePicker()
|
||||
cp.chatView.focusMessageInput()
|
||||
return cp.Picker.HandleEvent(event)
|
||||
}
|
||||
|
||||
func (cp *channelsPicker) update() {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ func NewModel(app *tview.Application, cfg *config.Config, token string) *Model {
|
|||
m.messagesList = newMessagesList(cfg, m)
|
||||
m.messageInput = newMessageInput(cfg, m)
|
||||
m.channelsPicker = newChannelsPicker(cfg, m)
|
||||
m.channelsPicker.SetCancelFunc(m.closePicker)
|
||||
|
||||
m.SetBackgroundLayerStyle(m.cfg.Theme.Dialog.BackgroundStyle.Style)
|
||||
m.buildLayout()
|
||||
|
|
|
|||
34
pkg/picker/events.go
Normal file
34
pkg/picker/events.go
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package picker
|
||||
|
||||
import (
|
||||
"github.com/ayn2op/tview"
|
||||
"github.com/gdamore/tcell/v3"
|
||||
)
|
||||
|
||||
type SelectedEvent struct {
|
||||
tcell.EventTime
|
||||
Item
|
||||
}
|
||||
|
||||
func newSelectedEvent(item Item) *SelectedEvent {
|
||||
return &SelectedEvent{Item: item}
|
||||
}
|
||||
|
||||
func (p *Picker) _select() tview.Command {
|
||||
index := p.list.Cursor()
|
||||
if index >= 0 && index < len(p.filtered) {
|
||||
item := p.filtered[index]
|
||||
return func() tcell.Event {
|
||||
return newSelectedEvent(item)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CancelEvent struct{ tcell.EventTime }
|
||||
|
||||
func cancel() tview.Command {
|
||||
return func() tcell.Event {
|
||||
return &CancelEvent{}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,19 +9,15 @@ import (
|
|||
"github.com/sahilm/fuzzy"
|
||||
)
|
||||
|
||||
type (
|
||||
SelectedFunc func(item Item)
|
||||
CancelFunc func()
|
||||
)
|
||||
// bottom border + value
|
||||
const inputHeight = 2
|
||||
|
||||
type Picker struct {
|
||||
*flex.Model
|
||||
input *tview.InputField
|
||||
list *list.Model
|
||||
|
||||
onSelected SelectedFunc
|
||||
onCancel CancelFunc
|
||||
keyMap *KeyMap
|
||||
keyMap *KeyMap
|
||||
|
||||
items Items
|
||||
filtered Items
|
||||
|
|
@ -49,8 +45,7 @@ func New() *Picker {
|
|||
|
||||
p.
|
||||
SetDirection(flex.DirectionRow).
|
||||
// bottom border + value
|
||||
AddItem(p.input, 2, 0, true).
|
||||
AddItem(p.input, inputHeight, 0, true).
|
||||
AddItem(p.list, 0, 1, false)
|
||||
|
||||
p.Update()
|
||||
|
|
@ -97,14 +92,6 @@ func (p *Picker) SetScrollBar(scrollBar *tview.ScrollBar) {
|
|||
p.list.SetScrollBar(scrollBar)
|
||||
}
|
||||
|
||||
func (p *Picker) SetSelectedFunc(onSelected SelectedFunc) {
|
||||
p.onSelected = onSelected
|
||||
}
|
||||
|
||||
func (p *Picker) SetCancelFunc(onCancel CancelFunc) {
|
||||
p.onCancel = onCancel
|
||||
}
|
||||
|
||||
func (p *Picker) ClearInput() {
|
||||
p.input.SetText("")
|
||||
}
|
||||
|
|
@ -128,15 +115,6 @@ func (p *Picker) Update() {
|
|||
p.onInputChanged("")
|
||||
}
|
||||
|
||||
func (p *Picker) onListSelected(index int) {
|
||||
if p.onSelected != nil {
|
||||
if index >= 0 && index < len(p.filtered) {
|
||||
item := p.filtered[index]
|
||||
p.onSelected(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Picker) onInputChanged(text string) {
|
||||
var fuzzied Items
|
||||
if text == "" {
|
||||
|
|
@ -167,14 +145,11 @@ func (p *Picker) HandleEvent(event tcell.Event) tview.Command {
|
|||
case keybind.Matches(event, p.keyMap.Bottom):
|
||||
p.list.HandleEvent(tcell.NewEventKey(tcell.KeyEnd, "", tcell.ModNone))
|
||||
return nil
|
||||
|
||||
case keybind.Matches(event, p.keyMap.Select):
|
||||
p.onListSelected(p.list.Cursor())
|
||||
return nil
|
||||
return p._select()
|
||||
case keybind.Matches(event, p.keyMap.Cancel):
|
||||
if p.onCancel != nil {
|
||||
p.onCancel()
|
||||
}
|
||||
return nil
|
||||
return cancel()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue