Added recent messages to UserInfoPopup (#1729)

There's a Refresh button added to the popup to refresh the users messages in the popup. Not automatic now while we figure out how fast/slow it would be.

Co-authored-by: dnsge <sagedanielr@gmail.com>
This commit is contained in:
0xRainy 2020-06-21 05:15:14 -07:00 committed by GitHub
parent c5f6fd7568
commit 0e564065ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 117 additions and 8 deletions

View file

@ -59,6 +59,11 @@ bool Channel::isEmpty() const
return this->name_.isEmpty(); return this->name_.isEmpty();
} }
bool Channel::hasMessages() const
{
return !this->messages_.empty();
}
LimitedQueueSnapshot<MessagePtr> Channel::getMessageSnapshot() LimitedQueueSnapshot<MessagePtr> Channel::getMessageSnapshot()
{ {
return this->messages_.getSnapshot(); return this->messages_.getSnapshot();

View file

@ -75,6 +75,8 @@ public:
void deleteMessage(QString messageID); void deleteMessage(QString messageID);
void clearMessages(); void clearMessages();
bool hasMessages() const;
QStringList modList; QStringList modList;
// CHANNEL INFO // CHANNEL INFO

View file

@ -223,8 +223,13 @@ public:
this->firstChunkOffset_, this->lastChunkEnd_); this->firstChunkOffset_, this->lastChunkEnd_);
} }
bool empty() const
{
return this->limit_ - this->space() == 0;
}
private: private:
qsizetype space() qsizetype space() const
{ {
size_t totalSize = 0; size_t totalSize = 0;
for (auto &chunk : *this->chunks_) for (auto &chunk : *this->chunks_)

View file

@ -5,6 +5,7 @@
#include "common/NetworkRequest.hpp" #include "common/NetworkRequest.hpp"
#include "controllers/accounts/AccountController.hpp" #include "controllers/accounts/AccountController.hpp"
#include "controllers/highlights/HighlightBlacklistUser.hpp" #include "controllers/highlights/HighlightBlacklistUser.hpp"
#include "messages/Message.hpp"
#include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchChannel.hpp"
#include "providers/twitch/api/Helix.hpp" #include "providers/twitch/api/Helix.hpp"
#include "providers/twitch/api/Kraken.hpp" #include "providers/twitch/api/Kraken.hpp"
@ -14,6 +15,7 @@
#include "util/PostToThread.hpp" #include "util/PostToThread.hpp"
#include "util/Shortcut.hpp" #include "util/Shortcut.hpp"
#include "widgets/Label.hpp" #include "widgets/Label.hpp"
#include "widgets/helper/ChannelView.hpp"
#include "widgets/helper/EffectLabel.hpp" #include "widgets/helper/EffectLabel.hpp"
#include "widgets/helper/Line.hpp" #include "widgets/helper/Line.hpp"
@ -26,6 +28,7 @@
const QString TEXT_VIEWS("Views: %1"); const QString TEXT_VIEWS("Views: %1");
const QString TEXT_FOLLOWERS("Followers: %1"); const QString TEXT_FOLLOWERS("Followers: %1");
const QString TEXT_CREATED("Created: %1"); const QString TEXT_CREATED("Created: %1");
const QString TEXT_TITLE("%1's Usercard");
#define TEXT_USER_ID "ID: " #define TEXT_USER_ID "ID: "
#define TEXT_UNAVAILABLE "(not available)" #define TEXT_UNAVAILABLE "(not available)"
@ -49,16 +52,48 @@ namespace {
return label.getElement(); return label.getElement();
}; };
ChannelPtr filterMessages(const QString &userName, ChannelPtr channel)
{
LimitedQueueSnapshot<MessagePtr> snapshot =
channel->getMessageSnapshot();
ChannelPtr channelPtr(
new Channel(channel->getName(), Channel::Type::None));
for (size_t i = 0; i < snapshot.size(); i++)
{
MessagePtr message = snapshot[i];
bool isSubscription =
message->flags.has(MessageFlag::Subscription) &&
message->loginName == "" &&
message->messageText.split(" ").at(0).compare(
userName, Qt::CaseInsensitive) == 0;
bool isModAction = message->timeoutUser.compare(
userName, Qt::CaseInsensitive) == 0;
bool isSelectedUser =
message->loginName.compare(userName, Qt::CaseInsensitive) == 0;
if ((isSubscription || isModAction || isSelectedUser) &&
!message->flags.has(MessageFlag::Whisper))
{
channelPtr->addMessage(message);
}
}
return channelPtr;
};
} // namespace } // namespace
UserInfoPopup::UserInfoPopup() UserInfoPopup::UserInfoPopup()
: BaseWindow({BaseWindow::Frameless, BaseWindow::FramelessDraggable}) : BaseWindow(BaseWindow::EnableCustomFrame)
, hack_(new bool) , hack_(new bool)
{ {
this->setWindowTitle("Usercard");
this->setStayInScreenRect(true); this->setStayInScreenRect(true);
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
this->setWindowFlag(Qt::Popup); this->setWindowFlag(Qt::Dialog);
#endif #endif
// Close the popup when Escape is pressed // Close the popup when Escape is pressed
@ -118,7 +153,8 @@ UserInfoPopup::UserInfoPopup()
.assign(&this->ui_.ignoreHighlights); .assign(&this->ui_.ignoreHighlights);
auto usercard = user.emplace<EffectLabel2>(this); auto usercard = user.emplace<EffectLabel2>(this);
usercard->getLabel().setText("Usercard"); usercard->getLabel().setText("Usercard");
auto refresh = user.emplace<EffectLabel2>(this);
refresh->getLabel().setText("Refresh");
auto mod = user.emplace<Button>(this); auto mod = user.emplace<Button>(this);
mod->setPixmap(getResources().buttons.mod); mod->setPixmap(getResources().buttons.mod);
mod->setScaleIndependantSize(30, 30); mod->setScaleIndependantSize(30, 30);
@ -134,6 +170,8 @@ UserInfoPopup::UserInfoPopup()
"/viewercard/" + this->userName_); "/viewercard/" + this->userName_);
}); });
QObject::connect(refresh.getElement(), &Button::leftClicked,
[this] { this->updateLatestMessages(); });
QObject::connect(mod.getElement(), &Button::leftClicked, [this] { QObject::connect(mod.getElement(), &Button::leftClicked, [this] {
this->channel_->sendMessage("/mod " + this->userName_); this->channel_->sendMessage("/mod " + this->userName_);
}); });
@ -215,8 +253,25 @@ UserInfoPopup::UserInfoPopup()
}); });
} }
this->installEvents(); layout.emplace<Line>(false);
// fourth line (last messages)
auto logs = layout.emplace<QVBoxLayout>().withoutMargin();
{
this->ui_.noMessagesLabel = new Label("No recent messages");
this->ui_.noMessagesLabel->setVisible(false);
this->ui_.latestMessages = new ChannelView(this);
this->ui_.latestMessages->setMinimumSize(400, 275);
this->ui_.latestMessages->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
logs->addWidget(this->ui_.noMessagesLabel);
logs->addWidget(this->ui_.latestMessages);
logs->setAlignment(this->ui_.noMessagesLabel, Qt::AlignHCenter);
}
this->installEvents();
this->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Policy::Ignored); this->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Policy::Ignored);
} }
@ -358,6 +413,7 @@ void UserInfoPopup::setData(const QString &name, const ChannelPtr &channel)
{ {
this->userName_ = name; this->userName_ = name;
this->channel_ = channel; this->channel_ = channel;
this->setWindowTitle(TEXT_TITLE.arg(name));
this->ui_.nameLabel->setText(name); this->ui_.nameLabel->setText(name);
this->ui_.nameLabel->setProperty("copy-text", name); this->ui_.nameLabel->setProperty("copy-text", name);
@ -365,6 +421,20 @@ void UserInfoPopup::setData(const QString &name, const ChannelPtr &channel)
this->updateUserData(); this->updateUserData();
this->userStateChanged_.invoke(); this->userStateChanged_.invoke();
this->updateLatestMessages();
QTimer::singleShot(1, this, [this] { this->setStayInScreenRect(true); });
}
void UserInfoPopup::updateLatestMessages()
{
auto filteredChannel = filterMessages(this->userName_, this->channel_);
this->ui_.latestMessages->setChannel(filteredChannel);
this->ui_.latestMessages->setSourceChannel(this->channel_);
const bool hasMessages = filteredChannel->hasMessages();
this->ui_.latestMessages->setVisible(hasMessages);
this->ui_.noMessagesLabel->setVisible(!hasMessages);
} }
void UserInfoPopup::updateUserData() void UserInfoPopup::updateUserData()

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "widgets/BaseWindow.hpp" #include "widgets/BaseWindow.hpp"
#include "widgets/helper/ChannelView.hpp"
#include <pajlada/signals/signal.hpp> #include <pajlada/signals/signal.hpp>
@ -28,6 +29,7 @@ protected:
private: private:
void installEvents(); void installEvents();
void updateUserData(); void updateUserData();
void updateLatestMessages();
void loadAvatar(const QUrl &url); void loadAvatar(const QUrl &url);
bool isMod_; bool isMod_;
@ -53,6 +55,10 @@ private:
QCheckBox *follow = nullptr; QCheckBox *follow = nullptr;
QCheckBox *ignore = nullptr; QCheckBox *ignore = nullptr;
QCheckBox *ignoreHighlights = nullptr; QCheckBox *ignoreHighlights = nullptr;
Label *noMessagesLabel = nullptr;
ChannelView *latestMessages = nullptr;
QPushButton *refreshButton = nullptr;
} ui_; } ui_;
class TimeoutWidget : public BaseWidget class TimeoutWidget : public BaseWidget

View file

@ -109,6 +109,7 @@ namespace {
ChannelView::ChannelView(BaseWidget *parent) ChannelView::ChannelView(BaseWidget *parent)
: BaseWidget(parent) : BaseWidget(parent)
, sourceChannel_(nullptr)
, scrollBar_(new Scrollbar(this)) , scrollBar_(new Scrollbar(this))
{ {
this->setMouseTracking(true); this->setMouseTracking(true);
@ -621,6 +622,21 @@ void ChannelView::setChannel(ChannelPtr channel)
} }
} }
ChannelPtr ChannelView::sourceChannel() const
{
return this->sourceChannel_;
}
void ChannelView::setSourceChannel(ChannelPtr sourceChannel)
{
this->sourceChannel_ = sourceChannel;
}
bool ChannelView::hasSourceChannel() const
{
return this->sourceChannel_ != nullptr;
}
void ChannelView::messageAppended(MessagePtr &message, void ChannelView::messageAppended(MessagePtr &message,
boost::optional<MessageFlags> overridingFlags) boost::optional<MessageFlags> overridingFlags)
{ {
@ -1791,8 +1807,8 @@ void ChannelView::hideEvent(QHideEvent *)
void ChannelView::showUserInfoPopup(const QString &userName) void ChannelView::showUserInfoPopup(const QString &userName)
{ {
auto *userPopup = new UserInfoPopup; auto *userPopup = new UserInfoPopup;
userPopup->setData(userName, this->channel_); userPopup->setData(userName, this->hasSourceChannel() ? this->sourceChannel_
userPopup->setActionOnFocusLoss(BaseWindow::Delete); : this->channel_);
QPoint offset(int(150 * this->scale()), int(70 * this->scale())); QPoint offset(int(150 * this->scale()), int(70 * this->scale()));
userPopup->move(QCursor::pos() - offset); userPopup->move(QCursor::pos() - offset);
userPopup->show(); userPopup->show();

View file

@ -76,6 +76,10 @@ public:
ChannelPtr channel(); ChannelPtr channel();
void setChannel(ChannelPtr channel_); void setChannel(ChannelPtr channel_);
ChannelPtr sourceChannel() const;
void setSourceChannel(ChannelPtr sourceChannel);
bool hasSourceChannel() const;
LimitedQueueSnapshot<MessageLayoutPtr> getMessagesSnapshot(); LimitedQueueSnapshot<MessageLayoutPtr> getMessagesSnapshot();
void queueLayout(); void queueLayout();
@ -174,6 +178,7 @@ private:
LimitedQueueSnapshot<MessageLayoutPtr> snapshot_; LimitedQueueSnapshot<MessageLayoutPtr> snapshot_;
ChannelPtr channel_; ChannelPtr channel_;
ChannelPtr sourceChannel_;
Scrollbar *scrollBar_; Scrollbar *scrollBar_;
EffectLabel *goToBottom_; EffectLabel *goToBottom_;