channels_picker.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package chat
  2. import (
  3. "log/slog"
  4. "strings"
  5. "github.com/ayn2op/discordo/internal/config"
  6. "github.com/ayn2op/discordo/internal/ui"
  7. "github.com/ayn2op/tview"
  8. "github.com/ayn2op/tview/help"
  9. "github.com/ayn2op/tview/keybind"
  10. "github.com/ayn2op/tview/picker"
  11. "github.com/diamondburned/arikawa/v3/discord"
  12. )
  13. type channelsPicker struct {
  14. *picker.Model
  15. chatView *Model
  16. browseMode bool
  17. }
  18. var _ help.KeyMap = (*channelsPicker)(nil)
  19. func newChannelsPicker(cfg *config.Config, chatView *Model) *channelsPicker {
  20. cp := &channelsPicker{Model: picker.NewModel(), chatView: chatView}
  21. ConfigurePicker(cp.Model, cfg, "Channels")
  22. return cp
  23. }
  24. // resetBrowse starts the channels picker in input mode so users can type to filter immediately.
  25. func (cp *channelsPicker) resetBrowse() { cp.browseMode = false }
  26. func (cp *channelsPicker) HandleEvent(event tview.Event) tview.Command {
  27. switch event := event.(type) {
  28. case *tview.KeyEvent:
  29. if cmd, handled := pickerBrowseHandleKey(event, &cp.browseMode, cp.Model, func() { cp.chatView.closePicker() }); handled {
  30. return cmd
  31. }
  32. case *picker.SelectedEvent:
  33. channelID, ok := event.Reference.(discord.ChannelID)
  34. if !ok || !channelID.IsValid() {
  35. return nil
  36. }
  37. channel, err := cp.chatView.state.Cabinet.Channel(channelID)
  38. if err != nil {
  39. slog.Error("failed to get channel from state", "err", err, "channel_id", channelID)
  40. return nil
  41. }
  42. node := cp.chatView.guildsTree.findNodeByChannelID(channel.ID)
  43. if node == nil {
  44. slog.Error("failed to locate channel in tree", "channel_id", channel.ID)
  45. return nil
  46. }
  47. cp.chatView.guildsTree.expandPathToNode(node)
  48. cp.chatView.guildsTree.SetCurrentNode(node)
  49. var selectCmd tview.Command
  50. if channel.Type != discord.GuildCategory {
  51. selectCmd = cp.chatView.guildsTree.onSelected(node)
  52. }
  53. cp.chatView.closePicker()
  54. return selectCmd
  55. case *picker.CancelEvent:
  56. cp.chatView.closePicker()
  57. return nil
  58. }
  59. return cp.Model.HandleEvent(event)
  60. }
  61. func (cp *channelsPicker) update() {
  62. var items picker.Items
  63. state := cp.chatView.state
  64. privateChannels, err := state.Cabinet.PrivateChannels()
  65. if err != nil {
  66. slog.Error("failed to get private channels from state", "err", err)
  67. return
  68. }
  69. ui.SortPrivateChannels(privateChannels)
  70. for _, channel := range privateChannels {
  71. items = append(items, cp.channelItem(nil, channel))
  72. }
  73. guilds, err := state.Cabinet.Guilds()
  74. if err != nil {
  75. slog.Error("failed to get guilds from state", "err", err)
  76. return
  77. }
  78. for _, guild := range guilds {
  79. channels, err := state.Cabinet.Channels(guild.ID)
  80. if err != nil {
  81. slog.Error("failed to get channels from state", "err", err, "guild_id", guild.ID)
  82. continue
  83. }
  84. for _, channel := range channels {
  85. items = append(items, cp.channelItem(&guild, channel))
  86. }
  87. }
  88. cp.Model.SetItems(items)
  89. }
  90. func (cp *channelsPicker) channelItem(guild *discord.Guild, channel discord.Channel) picker.Item {
  91. var b strings.Builder
  92. b.WriteString(ui.ChannelToString(channel, cp.chatView.cfg.Icons, cp.chatView.state))
  93. if guild != nil {
  94. b.WriteString(" - ")
  95. b.WriteString(guild.Name)
  96. }
  97. name := b.String()
  98. return picker.Item{Text: name, FilterText: name, Reference: channel.ID}
  99. }
  100. func (cp *channelsPicker) ShortHelp() []keybind.Keybind {
  101. return pickerShortHelp(cp.chatView.cfg.Keybinds.Picker)
  102. }
  103. func (cp *channelsPicker) FullHelp() [][]keybind.Keybind {
  104. return pickerFullHelp(cp.chatView.cfg.Keybinds.Picker)
  105. }