import { CursorShape, ItemFlag, MatchFlag, QLabel, QListWidget, QListWidgetItem, Shape, WidgetEventTypes, QSize, } from '@nodegui/nodegui'; import { CategoryChannel, Client, Collection, Constants, DQConstants, Guild, GuildChannel, Message, Permissions, } from 'discord.js'; import { app, MAX_QSIZE } from '../..'; import { Events as AppEvents } from '../../structures/Events'; import { createLogger } from '../../utilities/Console'; import { ViewOptions } from '../../views/ViewOptions'; import { ChannelButton } from './ChannelButton'; const { debug } = createLogger('ChannelsList'); export class ChannelsList extends QListWidget { private guild?: Guild; private active?: ChannelButton; private buttons: Set = new Set(); constructor() { super(); this.setFrameShape(Shape.NoFrame); this.setObjectName('ChannelsList'); this.setVerticalScrollMode(1); this.setSpacing(0); app.on(AppEvents.SWITCH_VIEW, this.handleSwitchView.bind(this)); app.on(AppEvents.NEW_CLIENT, this.handleEvents.bind(this)); } private handleEvents(client: Client) { const { Events } = Constants as unknown as DQConstants; client.on(Events.MESSAGE_ACK, (data: any) => { const button = [...this.buttons.values()] .find((btn) => btn.channel?.id === data.channel_id); if (button) button.setUnread(false); }); client.on(Events.MESSAGE_CREATE, (message: Message) => { const button = [...this.buttons.values()] .find((btn) => btn.channel?.id === message.channel.id); if (button) button.setUnread(true); }); } private async handleSwitchView(view: string, options?: ViewOptions) { if (view !== 'guild' || !options) return; let newGuild; if (options.guild) newGuild = options.guild; else if (options.channel) newGuild = options.channel.guild; else return; if (newGuild.id !== this.guild?.id) { this.guild = newGuild; await this.loadChannels(); } if (options.channel) { const chan = ([...this.nodeChildren.values()] as ChannelButton[]) .find((a) => a.channel === options.channel); this.active?.setActivated(false); chan?.setActivated(true); this.active = chan; } else this.active = undefined; } private minSize = new QSize(150, 36); async loadChannels() { const { guild, buttons } = this; if (!guild) return; debug(`Loading channels of guild ${guild.name} (${guild.id})...`); this.clear(); const [categories, channels] = guild.channels.cache .filter((c) => c.can(Permissions.FLAGS.VIEW_CHANNEL)) .partition((a) => a.type === 'category') as [ Collection, Collection ]; debug(`Loading ${categories.size} categories...`); for (const category of categories.sort((a, b) => a.rawPosition - b.rawPosition).values()) { const item = new QListWidgetItem(); const label = new QLabel(this); let isOpened = true; label.setObjectName('CategoryHeader'); label.setText(`▼  ${category.name}`); label.addEventListener(WidgetEventTypes.MouseButtonPress, () => { isOpened = !isOpened; label.setText(`${isOpened ? '▼' : '►'}  ${category.name}`); const channelIds = guild.channels.cache .filter((a) => a.parentID === category.id) .map((a) => a.id); for (const id of channelIds) { const chItem = this.findItems(id, MatchFlag.MatchExactly)[0]; this.setRowHidden(this.row(chItem), !isOpened); } }); label.setMinimumSize(0, 30); label.setCursor(CursorShape.PointingHandCursor); item.setText(category.id); item.setFlags(~ItemFlag.ItemIsEnabled); this.addItem(item); item.setSizeHint(label.size()); this.setItemWidget(item, label); label.adjustSize(); } debug(`Loading ${channels.size} channels...`); for (const channel of channels.sort((a, b) => b.rawPosition - a.rawPosition).values()) { const btn = new ChannelButton(this); const item = new QListWidgetItem(); const parentItems = channel.parentID ? this.findItems(channel.parentID, 0) : []; item.setFlags(~ItemFlag.ItemIsEnabled); btn.loadChannel(channel); btn.setMinimumSize(0, 32); btn.setMaximumSize(MAX_QSIZE, 32); item.setSizeHint(this.minSize); item.setText(channel.id); this.insertItem(parentItems && parentItems.length ? this.row(parentItems[0]) + 1 : 0, item); this.setItemWidget(item, btn); buttons.add(btn); btn.addEventListener(WidgetEventTypes.DeferredDelete, () => buttons.delete(btn)); } } }