From 4a140644257b960ecd22b49e0d3428631449ce5c Mon Sep 17 00:00:00 2001 From: pajlada Date: Sat, 2 Aug 2025 12:19:05 +0200 Subject: [PATCH] refactor: make chatter list its own widget (#6365) --- CHANGELOG.md | 1 + src/CMakeLists.txt | 2 + src/widgets/ChatterListWidget.cpp | 396 +++++++++++++++++++++++++++ src/widgets/ChatterListWidget.hpp | 22 ++ src/widgets/splits/Split.cpp | 417 ++--------------------------- src/widgets/splits/Split.hpp | 2 +- src/widgets/splits/SplitHeader.cpp | 4 +- 7 files changed, 449 insertions(+), 395 deletions(-) create mode 100644 src/widgets/ChatterListWidget.cpp create mode 100644 src/widgets/ChatterListWidget.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 5daae4fa..22df017f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ - Dev: Don't detach threads. (#6333) - Dev: Mini refactor of `TwitchAccount`. (#6182) - Dev: Refactored away some `getApp` usages in `WindowManager`. (#6194) +- Dev: Refactored the Chatter List window into its own widget. (#6365) - Dev: Simplified string literals to be a re-export of Qt functions. (#6175) - Dev: Fixed incorrect lua generation of static methods for typescript plugins. (#6190, #6223) - Dev: Merged top/bottom and left/right notebook layouts. (#6215) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 74588a8d..31d33ae2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -590,6 +590,8 @@ set(SOURCE_FILES widgets/BaseWidget.hpp widgets/BaseWindow.cpp widgets/BaseWindow.hpp + widgets/ChatterListWidget.cpp + widgets/ChatterListWidget.hpp widgets/DraggablePopup.cpp widgets/DraggablePopup.hpp widgets/FramelessEmbedWindow.cpp diff --git a/src/widgets/ChatterListWidget.cpp b/src/widgets/ChatterListWidget.cpp new file mode 100644 index 00000000..d9663c92 --- /dev/null +++ b/src/widgets/ChatterListWidget.cpp @@ -0,0 +1,396 @@ +#include "widgets/ChatterListWidget.hpp" + +#include "Application.hpp" +#include "controllers/accounts/AccountController.hpp" +#include "controllers/hotkeys/HotkeyController.hpp" +#include "providers/twitch/api/Helix.hpp" +#include "providers/twitch/TwitchAccount.hpp" // IWYU pragma: keep +#include "providers/twitch/TwitchChannel.hpp" +#include "singletons/Fonts.hpp" +#include "singletons/Theme.hpp" +#include "util/Helpers.hpp" + +#include +#include +#include +#include + +namespace chatterino { + +namespace { + +QString formatVIPListError(HelixListVIPsError error, const QString &message) +{ + using Error = HelixListVIPsError; + + QString errorMessage = QString("Failed to list VIPs - "); + + switch (error) + { + case Error::Forwarded: { + errorMessage += message; + } + break; + + case Error::Ratelimited: { + errorMessage += "You are being ratelimited by Twitch. Try " + "again in a few seconds."; + } + break; + + case Error::UserMissingScope: { + // TODO(pajlada): Phrase MISSING_REQUIRED_SCOPE + errorMessage += "Missing required scope. " + "Re-login with your " + "account and try again."; + } + break; + + case Error::UserNotAuthorized: { + // TODO(pajlada): Phrase MISSING_PERMISSION + errorMessage += "You don't have permission to " + "perform that action."; + } + break; + + case Error::UserNotBroadcaster: { + errorMessage += + "Due to Twitch restrictions, " + "this command can only be used by the broadcaster. " + "To see the list of VIPs you must use the Twitch website."; + } + break; + + case Error::Unknown: { + errorMessage += "An unknown error has occurred."; + } + break; + } + return errorMessage; +} + +QString formatModsError(HelixGetModeratorsError error, const QString &message) +{ + using Error = HelixGetModeratorsError; + + QString errorMessage = QString("Failed to get moderators: "); + + switch (error) + { + case Error::Forwarded: { + errorMessage += message; + } + break; + + case Error::UserMissingScope: { + errorMessage += "Missing required scope. " + "Re-login with your " + "account and try again."; + } + break; + + case Error::UserNotAuthorized: { + errorMessage += + "Due to Twitch restrictions, " + "this command can only be used by the broadcaster. " + "To see the list of mods you must use the Twitch website."; + } + break; + + case Error::Unknown: { + errorMessage += "An unknown error has occurred."; + } + break; + } + return errorMessage; +} + +QString formatChattersError(HelixGetChattersError error, const QString &message) +{ + using Error = HelixGetChattersError; + + QString errorMessage = QString("Failed to get chatters: "); + + switch (error) + { + case Error::Forwarded: { + errorMessage += message; + } + break; + + case Error::UserMissingScope: { + errorMessage += "Missing required scope. " + "Re-login with your " + "account and try again."; + } + break; + + case Error::UserNotAuthorized: { + errorMessage += + "Due to Twitch restrictions, " + "this command can only be used by moderators. " + "To see the list of chatters you must use the Twitch website."; + } + break; + + case Error::Unknown: { + errorMessage += "An unknown error has occurred."; + } + break; + } + return errorMessage; +} + +} // namespace + +ChatterListWidget::ChatterListWidget(const TwitchChannel *twitchChannel, + QWidget *parent) + : BaseWindow({}, parent) +{ + this->setWindowTitle("Chatter List - " + twitchChannel->getName()); + assert(twitchChannel != nullptr); + + this->setAttribute(Qt::WA_DeleteOnClose); + + auto *dockVbox = new QVBoxLayout(); + auto *searchBar = new QLineEdit(this); + + auto *chattersList = new QListWidget(); + auto *resultList = new QListWidget(); + + auto *loadingLabel = new QLabel("Loading..."); + searchBar->setPlaceholderText("Search User..."); + + auto formatListItemText = [](const QString &text) { + auto *item = new QListWidgetItem(); + item->setText(text); + item->setFont( + getApp()->getFonts()->getFont(FontStyle::ChatMedium, 1.0)); + return item; + }; + + auto addLabel = [this, formatListItemText, + chattersList](const QString &label) { + auto *formattedLabel = formatListItemText(label); + formattedLabel->setFlags(Qt::NoItemFlags); + formattedLabel->setForeground(this->theme->accent); + chattersList->addItem(formattedLabel); + }; + + auto addUserList = [=](const QStringList &users, QString label) { + if (users.isEmpty()) + { + return; + } + + addLabel(QString("%1 (%2)").arg(label, localizeNumbers(users.size()))); + + for (const auto &user : users) + { + chattersList->addItem(formatListItemText(user)); + } + chattersList->addItem(new QListWidgetItem()); + }; + + auto performListSearch = [=]() { + auto query = searchBar->text(); + if (query.isEmpty()) + { + resultList->hide(); + chattersList->show(); + return; + } + + auto results = chattersList->findItems(query, Qt::MatchContains); + chattersList->hide(); + resultList->clear(); + for (auto &item : results) + { + if (!item->text().contains("(")) + { + resultList->addItem(formatListItemText(item->text())); + } + } + resultList->show(); + }; + + auto loadChatters = [=](auto modList, auto vipList, bool isBroadcaster) { + getHelix()->getChatters( + twitchChannel->roomId(), + getApp()->getAccounts()->twitch.getCurrent()->getUserId(), 50000, + [=](const auto &chatters) { + auto broadcaster = twitchChannel->getName().toLower(); + QStringList chatterList; + QStringList modChatters; + QStringList vipChatters; + + bool addedBroadcaster = false; + for (auto chatter : chatters.chatters) + { + chatter = chatter.toLower(); + + if (!addedBroadcaster && chatter == broadcaster) + { + addedBroadcaster = true; + addLabel("Broadcaster"); + chattersList->addItem(broadcaster); + chattersList->addItem(new QListWidgetItem()); + continue; + } + + if (modList.contains(chatter)) + { + modChatters.append(chatter); + continue; + } + + if (vipList.contains(chatter)) + { + vipChatters.append(chatter); + continue; + } + + chatterList.append(chatter); + } + + modChatters.sort(); + vipChatters.sort(); + chatterList.sort(); + + if (isBroadcaster) + { + addUserList(modChatters, QString("Moderators")); + addUserList(vipChatters, QString("VIPs")); + } + else + { + addLabel("Moderators"); + chattersList->addItem( + "Moderators cannot check who is a moderator"); + chattersList->addItem(new QListWidgetItem()); + + addLabel("VIPs"); + chattersList->addItem( + "Moderators cannot check who is a VIP"); + chattersList->addItem(new QListWidgetItem()); + } + + addUserList(chatterList, QString("Chatters")); + + loadingLabel->hide(); + performListSearch(); + }, + [chattersList, formatListItemText](auto error, + const auto &message) { + auto errorMessage = formatChattersError(error, message); + chattersList->addItem(formatListItemText(errorMessage)); + }); + }; + + QObject::connect(searchBar, &QLineEdit::textEdited, this, + performListSearch); + + // Only broadcaster can get vips, mods can get chatters + if (twitchChannel->isBroadcaster()) + { + // Add moderators + getHelix()->getModerators( + twitchChannel->roomId(), 1000, + [=](const auto &mods) { + QSet modList; + for (const auto &mod : mods) + { + modList.insert(mod.userName.toLower()); + } + + // Add vips + getHelix()->getChannelVIPs( + twitchChannel->roomId(), + [=](const auto &vips) { + QSet vipList; + for (const auto &vip : vips) + { + vipList.insert(vip.userName.toLower()); + } + + // Add chatters + loadChatters(modList, vipList, true); + }, + [chattersList, formatListItemText](auto error, + const auto &message) { + auto errorMessage = formatVIPListError(error, message); + chattersList->addItem(formatListItemText(errorMessage)); + }); + }, + [chattersList, formatListItemText](auto error, + const auto &message) { + auto errorMessage = formatModsError(error, message); + chattersList->addItem(formatListItemText(errorMessage)); + }); + } + else if (twitchChannel->hasModRights()) + { + QSet modList; + QSet vipList; + loadChatters(modList, vipList, false); + } + else + { + chattersList->addItem( + formatListItemText("Due to Twitch restrictions, this feature is " + "only \navailable for moderators.")); + chattersList->addItem( + formatListItemText("If you would like to see the Chatter list, you " + "must \nuse the Twitch website.")); + loadingLabel->hide(); + } + + this->setMinimumWidth(300); + + auto listDoubleClick = [this](const QModelIndex &index) { + const auto itemText = index.data().toString(); + + if (!itemText.isEmpty()) + { + this->userClicked(itemText); + } + }; + + QObject::connect(chattersList, &QListWidget::doubleClicked, this, + listDoubleClick); + + QObject::connect(resultList, &QListWidget::doubleClicked, this, + listDoubleClick); + + HotkeyController::HotkeyMap actions{ + {"delete", + [this](const std::vector &) -> QString { + this->close(); + return ""; + }}, + {"accept", nullptr}, + {"reject", nullptr}, + {"scrollPage", nullptr}, + {"openTab", nullptr}, + {"search", + [searchBar](const std::vector &) -> QString { + searchBar->setFocus(); + searchBar->selectAll(); + return ""; + }}, + }; + + getApp()->getHotkeys()->shortcutsForCategory(HotkeyCategory::PopupWindow, + actions, this); + + dockVbox->addWidget(searchBar); + dockVbox->addWidget(loadingLabel); + dockVbox->addWidget(chattersList); + dockVbox->addWidget(resultList); + resultList->hide(); + + this->setStyleSheet(this->theme->splits.input.styleSheet); + this->setLayout(dockVbox); +} + +} // namespace chatterino diff --git a/src/widgets/ChatterListWidget.hpp b/src/widgets/ChatterListWidget.hpp new file mode 100644 index 00000000..bec8d8b0 --- /dev/null +++ b/src/widgets/ChatterListWidget.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "widgets/BaseWindow.hpp" + +#include +#include + +namespace chatterino { + +class TwitchChannel; + +class ChatterListWidget : public BaseWindow +{ + Q_OBJECT + +public: + ChatterListWidget(const TwitchChannel *twitchChannel, QWidget *parent); + + Q_SIGNAL void userClicked(QString userLogin); +}; + +} // namespace chatterino diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index b83b81aa..7e998934 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -8,7 +8,6 @@ #include "controllers/commands/CommandController.hpp" #include "controllers/hotkeys/HotkeyController.hpp" #include "controllers/notifications/NotificationController.hpp" -#include "providers/twitch/api/Helix.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchIrcServer.hpp" @@ -18,8 +17,8 @@ #include "singletons/Theme.hpp" #include "singletons/WindowManager.hpp" #include "util/CustomPlayer.hpp" -#include "util/Helpers.hpp" #include "util/StreamLink.hpp" +#include "widgets/ChatterListWidget.hpp" #include "widgets/dialogs/SelectChannelDialog.hpp" #include "widgets/dialogs/SelectChannelFiltersDialog.hpp" #include "widgets/dialogs/UserInfoPopup.hpp" @@ -40,7 +39,6 @@ #include #include -#include #include #include #include @@ -53,134 +51,6 @@ #include -namespace { - -using namespace chatterino; - -QString formatVIPListError(HelixListVIPsError error, const QString &message) -{ - using Error = HelixListVIPsError; - - QString errorMessage = QString("Failed to list VIPs - "); - - switch (error) - { - case Error::Forwarded: { - errorMessage += message; - } - break; - - case Error::Ratelimited: { - errorMessage += "You are being ratelimited by Twitch. Try " - "again in a few seconds."; - } - break; - - case Error::UserMissingScope: { - // TODO(pajlada): Phrase MISSING_REQUIRED_SCOPE - errorMessage += "Missing required scope. " - "Re-login with your " - "account and try again."; - } - break; - - case Error::UserNotAuthorized: { - // TODO(pajlada): Phrase MISSING_PERMISSION - errorMessage += "You don't have permission to " - "perform that action."; - } - break; - - case Error::UserNotBroadcaster: { - errorMessage += - "Due to Twitch restrictions, " - "this command can only be used by the broadcaster. " - "To see the list of VIPs you must use the Twitch website."; - } - break; - - case Error::Unknown: { - errorMessage += "An unknown error has occurred."; - } - break; - } - return errorMessage; -} - -QString formatModsError(HelixGetModeratorsError error, const QString &message) -{ - using Error = HelixGetModeratorsError; - - QString errorMessage = QString("Failed to get moderators: "); - - switch (error) - { - case Error::Forwarded: { - errorMessage += message; - } - break; - - case Error::UserMissingScope: { - errorMessage += "Missing required scope. " - "Re-login with your " - "account and try again."; - } - break; - - case Error::UserNotAuthorized: { - errorMessage += - "Due to Twitch restrictions, " - "this command can only be used by the broadcaster. " - "To see the list of mods you must use the Twitch website."; - } - break; - - case Error::Unknown: { - errorMessage += "An unknown error has occurred."; - } - break; - } - return errorMessage; -} - -QString formatChattersError(HelixGetChattersError error, const QString &message) -{ - using Error = HelixGetChattersError; - - QString errorMessage = QString("Failed to get chatters: "); - - switch (error) - { - case Error::Forwarded: { - errorMessage += message; - } - break; - - case Error::UserMissingScope: { - errorMessage += "Missing required scope. " - "Re-login with your " - "account and try again."; - } - break; - - case Error::UserNotAuthorized: { - errorMessage += - "Due to Twitch restrictions, " - "this command can only be used by moderators. " - "To see the list of chatters you must use the Twitch website."; - } - break; - - case Error::Unknown: { - errorMessage += "An unknown error has occurred."; - } - break; - } - return errorMessage; -} - -} // namespace - namespace chatterino { namespace { void showTutorialVideo(QWidget *parent, const QString &source, @@ -681,7 +551,7 @@ void Split::addShortcuts() }}, {"openViewerList", [this](const std::vector &) -> QString { - this->showChatterList(); + this->openChatterList(); return ""; }}, {"clearMessages", @@ -1147,14 +1017,20 @@ void Split::deleteFromContainer() void Split::changeChannel() { - this->showChangeChannelPopup("Change channel", false, [](bool) {}); + this->showChangeChannelPopup( + "Change channel", false, [this](bool didSelectChannel) { + if (!didSelectChannel) + { + return; + } - auto popup = this->findChildren(); - if (popup.size() && popup.at(0)->isVisible() && !popup.at(0)->isFloating()) - { - popup.at(0)->hide(); - showChatterList(); - } + // After changing channel (i.e. pressing OK in the channel switcher), close all open Chatter Lists + // We could consider updating the chatter list with the new channel + for (const auto &w : this->findChildren()) + { + w->close(); + } + }); } void Split::explainMoving() @@ -1253,26 +1129,8 @@ void Split::openWithCustomScheme() } } -void Split::showChatterList() +void Split::openChatterList() { - auto *chatterDock = new QDockWidget( - "Chatter List - " + this->getChannel()->getName(), this); - chatterDock->setAllowedAreas(Qt::LeftDockWidgetArea); - chatterDock->setFeatures(QDockWidget::DockWidgetVerticalTitleBar | - QDockWidget::DockWidgetClosable | - QDockWidget::DockWidgetFloatable); - chatterDock->resize( - 0.5 * this->width(), - this->height() - this->header_->height() - this->input_->height()); - chatterDock->move(0, this->header_->height()); - - auto *multiWidget = new QWidget(chatterDock); - auto *dockVbox = new QVBoxLayout(); - auto *searchBar = new QLineEdit(chatterDock); - - auto *chattersList = new QListWidget(); - auto *resultList = new QListWidget(); - auto channel = this->getChannel(); if (!channel) { @@ -1282,7 +1140,6 @@ void Split::showChatterList() } auto *twitchChannel = dynamic_cast(channel.get()); - if (twitchChannel == nullptr) { qCWarning(chatterinoWidget) @@ -1290,245 +1147,21 @@ void Split::showChatterList() return; } - auto *loadingLabel = new QLabel("Loading..."); - searchBar->setPlaceholderText("Search User..."); + const auto chatterListWidth = static_cast(this->width() * 0.5); + const auto chatterListHeight = + this->height() - this->header_->height() - this->input_->height(); - auto formatListItemText = [](QString text) { - auto *item = new QListWidgetItem(); - item->setText(text); - item->setFont( - getApp()->getFonts()->getFont(FontStyle::ChatMedium, 1.0)); - return item; - }; + auto *chatterDock = new ChatterListWidget(twitchChannel, this); - auto addLabel = [this, formatListItemText, chattersList](QString label) { - auto *formattedLabel = formatListItemText(label); - formattedLabel->setForeground(this->theme->accent); - chattersList->addItem(formattedLabel); - }; + QObject::connect(chatterDock, &ChatterListWidget::userClicked, + [this](const QString &userLogin) { + this->view_->showUserInfoPopup(userLogin); + }); - auto addUserList = [=](QStringList users, QString label) { - if (users.isEmpty()) - { - return; - } - - addLabel(QString("%1 (%2)").arg(label, localizeNumbers(users.size()))); - - for (const auto &user : users) - { - chattersList->addItem(formatListItemText(user)); - } - chattersList->addItem(new QListWidgetItem()); - }; - - auto performListSearch = [=]() { - auto query = searchBar->text(); - if (query.isEmpty()) - { - resultList->hide(); - chattersList->show(); - return; - } - - auto results = chattersList->findItems(query, Qt::MatchContains); - chattersList->hide(); - resultList->clear(); - for (auto &item : results) - { - if (!item->text().contains("(")) - { - resultList->addItem(formatListItemText(item->text())); - } - } - resultList->show(); - }; - - auto loadChatters = [=](auto modList, auto vipList, bool isBroadcaster) { - getHelix()->getChatters( - twitchChannel->roomId(), - getApp()->getAccounts()->twitch.getCurrent()->getUserId(), 50000, - [=](auto chatters) { - auto broadcaster = channel->getName().toLower(); - QStringList chatterList; - QStringList modChatters; - QStringList vipChatters; - - bool addedBroadcaster = false; - for (auto chatter : chatters.chatters) - { - chatter = chatter.toLower(); - - if (!addedBroadcaster && chatter == broadcaster) - { - addedBroadcaster = true; - addLabel("Broadcaster"); - chattersList->addItem(broadcaster); - chattersList->addItem(new QListWidgetItem()); - continue; - } - - if (modList.contains(chatter)) - { - modChatters.append(chatter); - continue; - } - - if (vipList.contains(chatter)) - { - vipChatters.append(chatter); - continue; - } - - chatterList.append(chatter); - } - - modChatters.sort(); - vipChatters.sort(); - chatterList.sort(); - - if (isBroadcaster) - { - addUserList(modChatters, QString("Moderators")); - addUserList(vipChatters, QString("VIPs")); - } - else - { - addLabel("Moderators"); - chattersList->addItem( - "Moderators cannot check who is a moderator"); - chattersList->addItem(new QListWidgetItem()); - - addLabel("VIPs"); - chattersList->addItem( - "Moderators cannot check who is a VIP"); - chattersList->addItem(new QListWidgetItem()); - } - - addUserList(chatterList, QString("Chatters")); - - loadingLabel->hide(); - performListSearch(); - }, - [chattersList, formatListItemText](auto error, auto message) { - auto errorMessage = formatChattersError(error, message); - chattersList->addItem(formatListItemText(errorMessage)); - }); - }; - - QObject::connect(searchBar, &QLineEdit::textEdited, this, - performListSearch); - - // Only broadcaster can get vips, mods can get chatters - if (channel->isBroadcaster()) - { - // Add moderators - getHelix()->getModerators( - twitchChannel->roomId(), 1000, - [=](auto mods) { - QSet modList; - for (const auto &mod : mods) - { - modList.insert(mod.userName.toLower()); - } - - // Add vips - getHelix()->getChannelVIPs( - twitchChannel->roomId(), - [=](auto vips) { - QSet vipList; - for (const auto &vip : vips) - { - vipList.insert(vip.userName.toLower()); - } - - // Add chatters - loadChatters(modList, vipList, true); - }, - [chattersList, formatListItemText](auto error, - auto message) { - auto errorMessage = formatVIPListError(error, message); - chattersList->addItem(formatListItemText(errorMessage)); - }); - }, - [chattersList, formatListItemText](auto error, auto message) { - auto errorMessage = formatModsError(error, message); - chattersList->addItem(formatListItemText(errorMessage)); - }); - } - else if (channel->hasModRights()) - { - QSet modList; - QSet vipList; - loadChatters(modList, vipList, false); - } - else - { - chattersList->addItem( - formatListItemText("Due to Twitch restrictions, this feature is " - "only \navailable for moderators.")); - chattersList->addItem( - formatListItemText("If you would like to see the Chatter list, you " - "must \nuse the Twitch website.")); - loadingLabel->hide(); - } - - QObject::connect(chatterDock, &QDockWidget::topLevelChanged, this, [=]() { - chatterDock->setMinimumWidth(300); - }); - - auto listDoubleClick = [this](const QModelIndex &index) { - const auto itemText = index.data().toString(); - - // if the list item contains a parentheses it means that - // it's a category label so don't show a usercard - if (!itemText.contains("(") && !itemText.isEmpty()) - { - this->view_->showUserInfoPopup(itemText); - } - }; - - QObject::connect(chattersList, &QListWidget::doubleClicked, this, - listDoubleClick); - - QObject::connect(resultList, &QListWidget::doubleClicked, this, - listDoubleClick); - - HotkeyController::HotkeyMap actions{ - {"delete", - [chatterDock](const std::vector &) -> QString { - chatterDock->close(); - return ""; - }}, - {"accept", nullptr}, - {"reject", nullptr}, - {"scrollPage", nullptr}, - {"openTab", nullptr}, - {"search", - [searchBar](const std::vector &) -> QString { - searchBar->setFocus(); - searchBar->selectAll(); - return ""; - }}, - }; - - getApp()->getHotkeys()->shortcutsForCategory(HotkeyCategory::PopupWindow, - actions, chatterDock); - - dockVbox->addWidget(searchBar); - dockVbox->addWidget(loadingLabel); - dockVbox->addWidget(chattersList); - dockVbox->addWidget(resultList); - resultList->hide(); - - multiWidget->setStyleSheet(this->theme->splits.input.styleSheet); - multiWidget->setLayout(dockVbox); - chatterDock->setWidget(multiWidget); - chatterDock->setFloating(true); + chatterDock->resize(chatterListWidth, chatterListHeight); widgets::showAndMoveWindowTo( chatterDock, this->mapToGlobal(QPoint{0, this->header_->height()}), widgets::BoundsChecking::CursorPosition); - chatterDock->activateWindow(); } void Split::openSubPage() diff --git a/src/widgets/splits/Split.hpp b/src/widgets/splits/Split.hpp index d97f19af..bd2b044a 100644 --- a/src/widgets/splits/Split.hpp +++ b/src/widgets/splits/Split.hpp @@ -190,7 +190,7 @@ public Q_SLOTS: void openWithCustomScheme(); void setFiltersDialog(); void showSearch(bool singleChannel); - void showChatterList(); + void openChatterList(); void openSubPage(); void reloadChannelAndSubscriberEmotes(); void reconnect(); diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index f7ba89e9..f20d9841 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -358,7 +358,7 @@ void SplitHeader::initializeLayout() // chatter list this->chattersButton_ = makeWidget([&](auto w) { QObject::connect(w, &Button::leftClicked, this, [this]() { - this->split_->showChatterList(); + this->split_->openChatterList(); }); }), // dropdown @@ -556,7 +556,7 @@ std::unique_ptr SplitHeader::createMainMenu() moreMenu->addAction( "Show chatter list", h->getDisplaySequence(HotkeyCategory::Split, "openViewerList"), - this->split_, &Split::showChatterList); + this->split_, &Split::openChatterList); } moreMenu->addAction("Subscribe",