discordo/internal/ui/chat/channelspicker/model.go

104 lines
2.5 KiB
Go

package channelspicker
import (
"log/slog"
"strings"
"github.com/ayn2op/arikawa/v3/discord"
"github.com/ayn2op/discordo/internal/config"
"github.com/ayn2op/discordo/internal/ui"
"github.com/ayn2op/ningen/v3"
"github.com/ayn2op/tview"
"github.com/ayn2op/tview/picker"
)
type Model struct {
items picker.Items
searchState picker.SearchState
cfg *config.Config
}
func NewModel(cfg *config.Config) *Model {
return &Model{searchState: picker.NewSearchState(), cfg: cfg}
}
var _ tview.Model = (*Model)(nil)
// actionMsg changes the picker.
type actionMsg picker.Action
func (*Model) Init() tview.Cmd { return nil }
// View shows the picker in a box titled Channels.
func (m *Model) View() tview.Element {
p := ui.Picker(m.items, &m.searchState, m.cfg).
OnAction(func(a picker.Action) tview.Msg { return actionMsg(a) }).
OnSelect(func(item picker.Item) tview.Msg {
channelID, ok := item.Reference.(discord.ChannelID)
if !ok || !channelID.IsValid() {
return nil
}
return SelectedMsg{ChannelID: channelID}
}).
OnCancel(CancelMsg{})
return ui.Box(p, &m.cfg.Theme, true).Title("Channels")
}
func (m *Model) Update(msg tview.Msg) tview.Cmd {
if msg, ok := msg.(actionMsg); ok {
m.searchState.Perform(picker.Action(msg))
}
return nil
}
// Reset clears the query.
func (m *Model) Reset() { m.searchState.Reset() }
func (m *Model) RefreshChannels(state *ningen.State) {
var items picker.Items
privateChannels, err := state.Cabinet.PrivateChannels()
if err != nil {
slog.Error("failed to get private channels from state", "err", err)
return
}
ui.SortPrivateChannels(privateChannels)
for _, channel := range privateChannels {
items = append(items, m.channelItem(state, nil, channel))
}
guilds, err := state.Cabinet.Guilds()
if err != nil {
slog.Error("failed to get guilds from state", "err", err)
return
}
for _, guild := range guilds {
channels, err := state.Cabinet.Channels(guild.ID)
if err != nil {
slog.Error("failed to get channels from state", "err", err, "guild_id", guild.ID)
continue
}
for _, channel := range channels {
items = append(items, m.channelItem(state, &guild, channel))
}
}
m.items = items
m.searchState.Reset()
}
func (m *Model) channelItem(state *ningen.State, guild *discord.Guild, channel discord.Channel) picker.Item {
var b strings.Builder
b.WriteString(ui.ChannelToString(channel, m.cfg.Icons, state))
if guild != nil {
b.WriteString(" - ")
b.WriteString(guild.Name)
}
name := b.String()
return picker.Item{Text: name, FilterText: name, Reference: channel.ID}
}