From 49449379da1a9fe2a865c139df487e2c4d1ca3b4 Mon Sep 17 00:00:00 2001 From: Rasmus Karlsson Date: Sat, 13 Oct 2018 14:20:06 +0200 Subject: [PATCH] Added a Live status indicator to tabs --- src/common/Channel.cpp | 5 ++ src/common/Channel.hpp | 1 + src/common/Common.hpp | 1 - src/providers/twitch/TwitchChannel.cpp | 2 - src/providers/twitch/TwitchChannel.hpp | 2 +- src/singletons/Theme.cpp | 8 --- src/singletons/Theme.hpp | 1 - src/widgets/helper/ChannelView.cpp | 5 +- src/widgets/helper/ChannelView.hpp | 1 + src/widgets/helper/NotebookTab.cpp | 27 ++++++-- src/widgets/helper/NotebookTab.hpp | 3 + src/widgets/splits/Split.cpp | 2 +- src/widgets/splits/SplitContainer.cpp | 88 +++++++++++++++++--------- src/widgets/splits/SplitContainer.hpp | 9 ++- 14 files changed, 104 insertions(+), 51 deletions(-) diff --git a/src/common/Channel.cpp b/src/common/Channel.cpp index d7321395..84b882c4 100644 --- a/src/common/Channel.cpp +++ b/src/common/Channel.cpp @@ -221,6 +221,11 @@ bool Channel::hasModRights() const return this->isMod() || this->isBroadcaster(); } +bool Channel::isLive() const +{ + return false; +} + std::shared_ptr Channel::getEmpty() { static std::shared_ptr channel(new Channel("", Type::None)); diff --git a/src/common/Channel.hpp b/src/common/Channel.hpp index 12382561..5d2d96db 100644 --- a/src/common/Channel.hpp +++ b/src/common/Channel.hpp @@ -69,6 +69,7 @@ public: virtual bool isMod() const; virtual bool isBroadcaster() const; virtual bool hasModRights() const; + virtual bool isLive() const; static std::shared_ptr getEmpty(); diff --git a/src/common/Common.hpp b/src/common/Common.hpp index bea206f7..7f22bf27 100644 --- a/src/common/Common.hpp +++ b/src/common/Common.hpp @@ -17,7 +17,6 @@ enum class HighlightState { None, Highlighted, NewMessage, - Notification, }; inline QString qS(const std::string &string) diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index f3523ffb..be38dce5 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -413,8 +413,6 @@ void TwitchChannel::setLive(bool newLiveStatus) } auto live = makeSystemMessage(this->getName() + " is live"); this->addMessage(live); - this->tabHighlightRequested.invoke( - HighlightState::Notification); } else { auto offline = makeSystemMessage(this->getName() + " is offline"); diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index a4a18013..1411e889 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -66,7 +66,7 @@ public: const QString &subscriptionUrl(); const QString &channelUrl(); const QString &popoutPlayerUrl(); - bool isLive() const; + virtual bool isLive() const override; QString roomId() const; AccessGuard accessRoomModes() const; AccessGuard accessStreamStatus() const; diff --git a/src/singletons/Theme.cpp b/src/singletons/Theme.cpp index 39272c4b..6a4d937a 100644 --- a/src/singletons/Theme.cpp +++ b/src/singletons/Theme.cpp @@ -105,10 +105,6 @@ void Theme::actuallyUpdate(double hue, double multiplier) QColor("#000"), {QColor("#b4d7ff"), QColor("#b4d7ff"), QColor("#b4d7ff")}, {QColor("#00aeef"), QColor("#00aeef"), QColor("#00aeef")}}; - this->tabs.notified = { - fg, - {QColor("#fff"), QColor("#fff"), QColor("#fff")}, - {QColor("#F824A8"), QColor("#F824A8"), QColor("#F824A8")}}; } else { this->tabs.regular = { QColor("#aaa"), @@ -127,10 +123,6 @@ void Theme::actuallyUpdate(double hue, double multiplier) QColor("#fff"), {QColor("#555555"), QColor("#555555"), QColor("#555555")}, {QColor("#00aeef"), QColor("#00aeef"), QColor("#00aeef")}}; - this->tabs.notified = { - fg, - {QColor("#252525"), QColor("#252525"), QColor("#252525")}, - {QColor("#F824A8"), QColor("#F824A8"), QColor("#F824A8")}}; } this->splits.input.focusedLine = highlighted; diff --git a/src/singletons/Theme.hpp b/src/singletons/Theme.hpp index d301d21a..2267b68f 100644 --- a/src/singletons/Theme.hpp +++ b/src/singletons/Theme.hpp @@ -50,7 +50,6 @@ public: TabColors newMessage; TabColors highlighted; TabColors selected; - TabColors notified; QColor border; QColor bottomLine; } tabs; diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 8c2c6021..d00859d5 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -555,7 +555,10 @@ void ChannelView::setChannel(ChannelPtr newChannel) TwitchChannel *tc = dynamic_cast(newChannel.get()); if (tc != nullptr) { tc->tabHighlightRequested.connect([this](HighlightState state) { - this->tabHighlightRequested.invoke(HighlightState::Notification); + this->tabHighlightRequested.invoke(state); + }); + tc->liveStatusChanged.connect([this]() { + this->liveStatusChanged.invoke(); // }); } } diff --git a/src/widgets/helper/ChannelView.hpp b/src/widgets/helper/ChannelView.hpp index 512439e3..3cd602a1 100644 --- a/src/widgets/helper/ChannelView.hpp +++ b/src/widgets/helper/ChannelView.hpp @@ -61,6 +61,7 @@ public: pajlada::Signals::Signal mouseDown; pajlada::Signals::NoArgSignal selectionChanged; pajlada::Signals::Signal tabHighlightRequested; + pajlada::Signals::NoArgSignal liveStatusChanged; pajlada::Signals::Signal linkClicked; pajlada::Signals::Signal joinToChannel; diff --git a/src/widgets/helper/NotebookTab.cpp b/src/widgets/helper/NotebookTab.cpp index 8875a4ca..fe05303c 100644 --- a/src/widgets/helper/NotebookTab.cpp +++ b/src/widgets/helper/NotebookTab.cpp @@ -168,13 +168,20 @@ void NotebookTab::setSelected(bool value) this->update(); } +void NotebookTab::setLive(bool isLive) +{ + if (this->isLive_ != isLive) { + this->isLive_ = isLive; + this->update(); + } +} + void NotebookTab::setHighlightState(HighlightState newHighlightStyle) { if (this->isSelected() || !this->highlightEnabled_) { return; } - if (this->highlightState_ != HighlightState::Highlighted && - this->highlightState_ != HighlightState::Notification) { + if (this->highlightState_ != HighlightState::Highlighted) { this->highlightState_ = newHighlightStyle; this->update(); @@ -252,8 +259,6 @@ void NotebookTab::paintEvent(QPaintEvent *) colors = this->theme->tabs.selected; } else if (this->highlightState_ == HighlightState::Highlighted) { colors = this->theme->tabs.highlighted; - } else if (this->highlightState_ == HighlightState::Notification) { - colors = this->theme->tabs.notified; } else if (this->highlightState_ == HighlightState::NewMessage) { colors = this->theme->tabs.newMessage; } else { @@ -297,6 +302,20 @@ void NotebookTab::paintEvent(QPaintEvent *) ? colors.line.hover : (windowFocused ? colors.line.regular : colors.line.unfocused)); + // draw live indicator + if (this->isLive_) { + painter.setPen(QColor(Qt::GlobalColor::red)); + QBrush b; + b.setColor(QColor(Qt::GlobalColor::red)); + b.setStyle(Qt::SolidPattern); + painter.setBrush(b); + + auto x = this->width() - (6.f * scale); + auto y = 4.f * scale; + auto diameter = 4.f * scale; + painter.drawEllipse(QRectF(x, y, diameter, diameter)); + } + // set the pen color painter.setPen(colors.text); diff --git a/src/widgets/helper/NotebookTab.hpp b/src/widgets/helper/NotebookTab.hpp index 4ec931ac..0e888961 100644 --- a/src/widgets/helper/NotebookTab.hpp +++ b/src/widgets/helper/NotebookTab.hpp @@ -39,6 +39,7 @@ public: bool isSelected() const; void setSelected(bool value); + void setLive(bool isLive); void setHighlightState(HighlightState style); void setHighlightsEnabled(const bool &newVal); bool hasHighlightsEnabled() const; @@ -88,6 +89,8 @@ private: bool highlightEnabled_ = true; QAction *highlightNewMessagesAction_; + bool isLive_{}; + QMenu menu_; std::vector managedConnections_; diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index d67652d5..34d00a5b 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -290,7 +290,7 @@ void Split::showChangeChannelPopup(const char *dialogTitle, bool empty, if (dialog->hasSeletedChannel()) { this->setChannel(dialog->getSelectedChannel()); if (this->isInContainer()) { - this->container_->refreshTabTitle(); + this->container_->refreshTab(); } } diff --git a/src/widgets/splits/SplitContainer.cpp b/src/widgets/splits/SplitContainer.cpp index a4de3e6d..61d465c2 100644 --- a/src/widgets/splits/SplitContainer.cpp +++ b/src/widgets/splits/SplitContainer.cpp @@ -84,7 +84,7 @@ void SplitContainer::setTab(NotebookTab *_tab) this->tab_->page = this; - this->refreshTabTitle(); + this->refreshTab(); } void SplitContainer::hideResizeHandles() @@ -177,7 +177,7 @@ void SplitContainer::addSplit(Split *split) this->unsetCursor(); this->splits_.push_back(split); - this->refreshTabTitle(); + this->refreshTab(); split->getChannelView().tabHighlightRequested.connect( [this](HighlightState state) { @@ -186,6 +186,10 @@ void SplitContainer::addSplit(Split *split) } }); + split->getChannelView().liveStatusChanged.connect([this]() { + this->refreshTabLiveStatus(); // + }); + split->focused.connect([this, split] { this->setSelected(split); }); this->layout(); @@ -228,7 +232,7 @@ SplitContainer::Position SplitContainer::releaseSplit(Split *split) this->splits_.front()->giveFocus(Qt::MouseFocusReason); } - this->refreshTabTitle(); + this->refreshTab(); // fourtf: really bad split->getChannelView().tabHighlightRequested.disconnectAll(); @@ -568,34 +572,10 @@ void SplitContainer::focusInEvent(QFocusEvent *) } } -void SplitContainer::refreshTabTitle() +void SplitContainer::refreshTab() { - if (this->tab_ == nullptr) { - return; - } - - QString newTitle = ""; - bool first = true; - - for (const auto &chatWidget : this->splits_) { - auto channelName = chatWidget->getChannel()->getName(); - if (channelName.isEmpty()) { - continue; - } - - if (!first) { - newTitle += ", "; - } - newTitle += channelName; - - first = false; - } - - if (newTitle.isEmpty()) { - newTitle = "empty"; - } - - this->tab_->setDefaultTitle(newTitle); + this->refreshTabTitle(); + this->refreshTabLiveStatus(); } int SplitContainer::getSplitCount() @@ -677,6 +657,54 @@ void SplitContainer::decodeNodeRecusively(QJsonObject &obj, Node *node) } } +void SplitContainer::refreshTabTitle() +{ + if (this->tab_ == nullptr) { + return; + } + + QString newTitle = ""; + bool first = true; + + for (const auto &chatWidget : this->splits_) { + auto channelName = chatWidget->getChannel()->getName(); + if (channelName.isEmpty()) { + continue; + } + + if (!first) { + newTitle += ", "; + } + newTitle += channelName; + + first = false; + } + + if (newTitle.isEmpty()) { + newTitle = "empty"; + } + + this->tab_->setDefaultTitle(newTitle); +} + +void SplitContainer::refreshTabLiveStatus() +{ + if (this->tab_ == nullptr) { + return; + } + + bool liveStatus = false; + for (const auto &s : this->splits_) { + auto c = s->getChannel(); + if (c->isLive()) { + liveStatus = true; + break; + } + } + + this->tab_->setLive(liveStatus); +} + // // Node // diff --git a/src/widgets/splits/SplitContainer.hpp b/src/widgets/splits/SplitContainer.hpp index 33604ba7..a2993003 100644 --- a/src/widgets/splits/SplitContainer.hpp +++ b/src/widgets/splits/SplitContainer.hpp @@ -171,7 +171,7 @@ private: public: SplitContainer(Notebook *parent); - Split* appendNewSplit(bool openChannelNameDialog); + Split *appendNewSplit(bool openChannelNameDialog); void appendSplit(Split *split); void insertSplit(Split *split, const Position &position); void insertSplit(Split *split, Direction direction, Split *relativeTo); @@ -186,7 +186,9 @@ public: int getSplitCount(); const std::vector getSplits() const; - void refreshTabTitle(); + + void refreshTab(); + NotebookTab *getTab() const; Node *getBaseNode(); @@ -221,6 +223,9 @@ private: void decodeNodeRecusively(QJsonObject &obj, Node *node); Split *getTopRightSplit(Node &node); + void refreshTabTitle(); + void refreshTabLiveStatus(); + struct DropRegion { QRect rect; std::pair position;