Add option to subscribe to and pin reply threads (#4680)

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
nerix
2023-06-17 17:41:52 +02:00
committed by GitHub
parent 2d3d3ae46e
commit aff9342647
15 changed files with 194 additions and 69 deletions
+30 -1
View File
@@ -1,4 +1,8 @@
#include "DraggablePopup.hpp"
#include "widgets/DraggablePopup.hpp"
#include "singletons/Resources.hpp"
#include "singletons/Theme.hpp"
#include "widgets/helper/Button.hpp"
#include <QMouseEvent>
@@ -90,4 +94,29 @@ void DraggablePopup::mouseMoveEvent(QMouseEvent *event)
}
}
Button *DraggablePopup::createPinButton()
{
auto *button = new Button(this);
button->setPixmap(getTheme()->buttons.pin);
button->setScaleIndependantSize(18, 18);
button->setToolTip("Pin Window");
bool pinned = false;
QObject::connect(
button, &Button::leftClicked, [this, button, pinned]() mutable {
pinned = !pinned;
if (pinned)
{
this->setActionOnFocusLoss(BaseWindow::Nothing);
button->setPixmap(getResources().buttons.pinEnabled);
}
else
{
this->setActionOnFocusLoss(BaseWindow::Delete);
button->setPixmap(getTheme()->buttons.pin);
}
});
return button;
}
} // namespace chatterino
+5
View File
@@ -26,6 +26,11 @@ protected:
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
/// Creates a pin button that is scoped to this window.
/// When clicked, the user can toggle whether the window is pinned.
/// The window is considered unpinned at the start.
Button *createPinButton();
// lifetimeHack_ is used to check that the window hasn't been destroyed yet
std::shared_ptr<bool> lifetimeHack_;
+69 -5
View File
@@ -7,16 +7,18 @@
#include "controllers/hotkeys/HotkeyController.hpp"
#include "messages/Message.hpp"
#include "messages/MessageThread.hpp"
#include "providers/twitch/ChannelPointReward.hpp"
#include "providers/twitch/TwitchAccount.hpp"
#include "providers/twitch/TwitchChannel.hpp"
#include "singletons/Settings.hpp"
#include "util/LayoutCreator.hpp"
#include "widgets/helper/Button.hpp"
#include "widgets/helper/ChannelView.hpp"
#include "widgets/helper/ResizingTextEdit.hpp"
#include "widgets/Scrollbar.hpp"
#include "widgets/splits/Split.hpp"
#include "widgets/splits/SplitInput.hpp"
#include <QCheckBox>
const QString TEXT_TITLE("Reply Thread - @%1 in #%2");
namespace chatterino {
@@ -72,9 +74,6 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, QWidget *parent,
this->shortcuts_ = getApp()->hotkeys->shortcutsForCategory(
HotkeyCategory::PopupWindow, actions, this);
auto layout = LayoutCreator<QWidget>(this->getLayoutContainer())
.setLayoutType<QVBoxLayout>();
// initialize UI
this->ui_.threadView =
new ChannelView(this, this->split_, ChannelView::Context::ReplyThread);
@@ -110,10 +109,57 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, QWidget *parent,
}
});
auto layout = LayoutCreator<QWidget>(this->getLayoutContainer())
.setLayoutType<QVBoxLayout>();
layout->setSpacing(0);
// provide draggable margin if frameless
auto marginPx = closeAutomatically ? 15 : 1;
layout->setContentsMargins(marginPx, marginPx, marginPx, marginPx);
// Top Row
bool addCheckbox = getSettings()->enableThreadHighlight;
if (addCheckbox || closeAutomatically)
{
auto *hbox = new QHBoxLayout();
if (addCheckbox)
{
this->ui_.notificationCheckbox =
new QCheckBox("Subscribe to thread", this);
QObject::connect(this->ui_.notificationCheckbox,
&QCheckBox::toggled, [this](bool checked) {
if (!this->thread_ ||
this->thread_->subscribed() == checked)
{
return;
}
if (checked)
{
this->thread_->markSubscribed();
}
else
{
this->thread_->markUnsubscribed();
}
});
hbox->addWidget(this->ui_.notificationCheckbox, 1);
}
if (closeAutomatically)
{
hbox->addWidget(this->createPinButton(), 0, Qt::AlignRight);
hbox->setContentsMargins(0, 0, 0, 5);
}
else
{
hbox->setContentsMargins(10, 0, 0, 4);
}
layout->addLayout(hbox, 1);
}
layout->addWidget(this->ui_.threadView, 1);
layout->addWidget(this->ui_.replyInput);
}
@@ -124,6 +170,24 @@ void ReplyThreadPopup::setThread(std::shared_ptr<MessageThread> thread)
this->ui_.replyInput->setReply(this->thread_);
this->addMessagesFromThread();
this->updateInputUI();
if (!this->thread_) [[unlikely]]
{
this->replySubscriptionSignal_ = boost::signals2::scoped_connection{};
return;
}
auto updateCheckbox = [this]() {
if (this->ui_.notificationCheckbox)
{
this->ui_.notificationCheckbox->setChecked(
this->thread_->subscribed());
}
};
updateCheckbox();
this->replySubscriptionSignal_ =
this->thread_->subscriptionUpdated.connect(updateCheckbox);
}
void ReplyThreadPopup::addMessagesFromThread()
+5
View File
@@ -7,6 +7,8 @@
#include <pajlada/signals/scoped-connection.hpp>
#include <pajlada/signals/signal.hpp>
class QCheckBox;
namespace chatterino {
class MessageThread;
@@ -41,10 +43,13 @@ private:
struct {
ChannelView *threadView = nullptr;
SplitInput *replyInput = nullptr;
QCheckBox *notificationCheckbox = nullptr;
} ui_;
std::unique_ptr<pajlada::Signals::ScopedConnection> messageConnection_;
std::vector<boost::signals2::scoped_connection> bSignals_;
boost::signals2::scoped_connection replySubscriptionSignal_;
};
} // namespace chatterino
+1 -32
View File
@@ -142,7 +142,6 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent,
"split being nullptr causes lots of bugs down the road");
this->setWindowTitle("Usercard");
this->setStayInScreenRect(true);
this->updateFocusLoss();
HotkeyController::HotkeyMap actions{
{"delete",
@@ -361,17 +360,7 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent,
// button to pin the window (only if we close automatically)
if (this->closeAutomatically_)
{
this->ui_.pinButton = box.emplace<Button>().getElement();
this->ui_.pinButton->setPixmap(
getApp()->themes->buttons.pin);
this->ui_.pinButton->setScaleIndependantSize(18, 18);
this->ui_.pinButton->setToolTip("Pin Window");
QObject::connect(this->ui_.pinButton, &Button::leftClicked,
[this]() {
this->closeAutomatically_ =
!this->closeAutomatically_;
this->updateFocusLoss();
});
box->addWidget(this->createPinButton());
}
}
@@ -920,26 +909,6 @@ void UserInfoPopup::updateUserData()
this->ui_.ignoreHighlights->setEnabled(false);
}
void UserInfoPopup::updateFocusLoss()
{
if (this->closeAutomatically_)
{
this->setActionOnFocusLoss(BaseWindow::Delete);
if (this->ui_.pinButton != nullptr)
{
this->ui_.pinButton->setPixmap(getApp()->themes->buttons.pin);
}
}
else
{
this->setActionOnFocusLoss(BaseWindow::Nothing);
if (this->ui_.pinButton != nullptr)
{
this->ui_.pinButton->setPixmap(getResources().buttons.pinEnabled);
}
}
}
void UserInfoPopup::loadAvatar(const QUrl &url)
{
QNetworkRequest req(url);
-3
View File
@@ -37,7 +37,6 @@ private:
void installEvents();
void updateUserData();
void updateLatestMessages();
void updateFocusLoss();
void loadAvatar(const QUrl &url);
bool isMod_;
@@ -73,8 +72,6 @@ private:
Label *followerCountLabel = nullptr;
Label *createdDateLabel = nullptr;
Label *userIDLabel = nullptr;
// Can be uninitialized if usercard is not configured to close on focus loss
Button *pinButton = nullptr;
Label *followageLabel = nullptr;
Label *subageLabel = nullptr;
@@ -916,6 +916,13 @@ void GeneralPage::initLayout(GeneralPageView &layout)
"Highlight received inline whispers", s.highlightInlineWhispers, false,
"Highlight the whispers shown in all splits.\nIf \"Show Twitch "
"whispers inline\" is disabled, this setting will do nothing.");
layout.addCheckbox(
"Automatically subscribe to participated reply threads",
s.autoSubToParticipatedThreads, false,
"When enabled, you will automatically subscribe to reply threads you "
"participate in.\n"
"This means reply threads you participate in will use your "
"\"Subscribed Reply Threads\" highlight settings.");
layout.addCheckbox("Load message history on connect",
s.loadTwitchMessageHistoryOnConnect);
// TODO: Change phrasing to use better english once we can tag settings, right now it's kept as history instead of historical so that the setting shows up when the user searches for history