channels_picker.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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/discordo/pkg/picker"
  8. "github.com/ayn2op/tview"
  9. "github.com/ayn2op/tview/help"
  10. "github.com/ayn2op/tview/keybind"
  11. "github.com/diamondburned/arikawa/v3/discord"
  12. )
  13. type channelsPicker struct {
  14. *picker.Picker
  15. chatView *View
  16. }
  17. var _ help.KeyMap = (*channelsPicker)(nil)
  18. func newChannelsPicker(cfg *config.Config, chatView *View) *channelsPicker {
  19. cp := &channelsPicker{picker.New(), chatView}
  20. cp.Box = ui.ConfigureBox(tview.NewBox(), &cfg.Theme)
  21. // When a child of tview.Flex is focused, tview.Flex itself is not reported as focused. Instead, the focused child (picker) is considered focused. Therefore, we manually set the active border style on the picker to ensure it displays the correct focused appearance.
  22. cp.
  23. SetBlurFunc(nil).
  24. SetFocusFunc(nil).
  25. SetBorderSet(cfg.Theme.Border.ActiveSet.BorderSet).
  26. SetBorderStyle(cfg.Theme.Border.ActiveStyle.Style).
  27. SetTitleStyle(cfg.Theme.Title.ActiveStyle.Style).
  28. SetFooterStyle(cfg.Theme.Footer.ActiveStyle.Style)
  29. cp.SetSelectedFunc(cp.onSelected)
  30. cp.SetTitle("Channels")
  31. cp.SetScrollBarVisibility(cfg.Theme.ScrollBar.Visibility.ScrollBarVisibility)
  32. cp.SetScrollBar(tview.NewScrollBar().
  33. SetTrackStyle(cfg.Theme.ScrollBar.TrackStyle.Style).
  34. SetThumbStyle(cfg.Theme.ScrollBar.ThumbStyle.Style).
  35. SetGlyphSet(cfg.Theme.ScrollBar.GlyphSet.GlyphSet))
  36. cp.SetKeyMap(&picker.KeyMap{
  37. Cancel: cfg.Keybinds.Picker.Cancel.Keybind,
  38. Up: cfg.Keybinds.Picker.Up.Keybind,
  39. Down: cfg.Keybinds.Picker.Down.Keybind,
  40. Top: cfg.Keybinds.Picker.Top.Keybind,
  41. Bottom: cfg.Keybinds.Picker.Bottom.Keybind,
  42. Select: cfg.Keybinds.Picker.Select.Keybind,
  43. })
  44. return cp
  45. }
  46. func (cp *channelsPicker) onSelected(item picker.Item) {
  47. channelID, ok := item.Reference.(discord.ChannelID)
  48. if !ok || !channelID.IsValid() {
  49. return
  50. }
  51. channel, err := cp.chatView.state.Cabinet.Channel(channelID)
  52. if err != nil {
  53. slog.Error("failed to get channel from state", "err", err, "channel_id", channelID)
  54. return
  55. }
  56. node := cp.chatView.guildsTree.findNodeByChannelID(channel.ID)
  57. if node == nil {
  58. slog.Error("failed to locate channel in tree", "channel_id", channel.ID)
  59. return
  60. }
  61. cp.chatView.guildsTree.expandPathToNode(node)
  62. cp.chatView.guildsTree.SetCurrentNode(node)
  63. if channel.Type != discord.GuildCategory {
  64. cp.chatView.guildsTree.onSelected(node)
  65. }
  66. cp.chatView.closePicker()
  67. cp.chatView.focusMessageInput()
  68. }
  69. func (cp *channelsPicker) update() {
  70. cp.ClearItems()
  71. state := cp.chatView.state
  72. privateChannels, err := state.Cabinet.PrivateChannels()
  73. if err != nil {
  74. slog.Error("failed to get private channels from state", "err", err)
  75. return
  76. }
  77. ui.SortPrivateChannels(privateChannels)
  78. for _, channel := range privateChannels {
  79. cp.addChannel(nil, channel)
  80. }
  81. guilds, err := state.Cabinet.Guilds()
  82. if err != nil {
  83. slog.Error("failed to get guilds from state", "err", err)
  84. return
  85. }
  86. for _, guild := range guilds {
  87. channels, err := state.Cabinet.Channels(guild.ID)
  88. if err != nil {
  89. slog.Error("failed to get channels from state", "err", err, "guild_id", guild.ID)
  90. continue
  91. }
  92. for _, channel := range channels {
  93. cp.addChannel(&guild, channel)
  94. }
  95. }
  96. cp.Update()
  97. }
  98. func (cp *channelsPicker) addChannel(guild *discord.Guild, channel discord.Channel) {
  99. var b strings.Builder
  100. b.WriteString(ui.ChannelToString(channel, cp.chatView.cfg.Icons, cp.chatView.state))
  101. if guild != nil {
  102. b.WriteString(" - ")
  103. b.WriteString(guild.Name)
  104. }
  105. name := b.String()
  106. cp.AddItem(picker.Item{Text: name, FilterText: name, Reference: channel.ID})
  107. }
  108. func (cp *channelsPicker) ShortHelp() []keybind.Keybind {
  109. cfg := cp.chatView.cfg.Keybinds.Picker
  110. return []keybind.Keybind{cfg.Up.Keybind, cfg.Down.Keybind, cfg.Select.Keybind, cfg.Cancel.Keybind}
  111. }
  112. func (cp *channelsPicker) FullHelp() [][]keybind.Keybind {
  113. cfg := cp.chatView.cfg.Keybinds.Picker
  114. return [][]keybind.Keybind{
  115. {cfg.Up.Keybind, cfg.Down.Keybind, cfg.Top.Keybind, cfg.Bottom.Keybind},
  116. {cfg.Select.Keybind, cfg.Cancel.Keybind},
  117. }
  118. }