mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Added a Live status indicator to tabs
This commit is contained in:
parent
71a51d34c7
commit
49449379da
|
@ -221,6 +221,11 @@ bool Channel::hasModRights() const
|
||||||
return this->isMod() || this->isBroadcaster();
|
return this->isMod() || this->isBroadcaster();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Channel::isLive() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Channel> Channel::getEmpty()
|
std::shared_ptr<Channel> Channel::getEmpty()
|
||||||
{
|
{
|
||||||
static std::shared_ptr<Channel> channel(new Channel("", Type::None));
|
static std::shared_ptr<Channel> channel(new Channel("", Type::None));
|
||||||
|
|
|
@ -69,6 +69,7 @@ public:
|
||||||
virtual bool isMod() const;
|
virtual bool isMod() const;
|
||||||
virtual bool isBroadcaster() const;
|
virtual bool isBroadcaster() const;
|
||||||
virtual bool hasModRights() const;
|
virtual bool hasModRights() const;
|
||||||
|
virtual bool isLive() const;
|
||||||
|
|
||||||
static std::shared_ptr<Channel> getEmpty();
|
static std::shared_ptr<Channel> getEmpty();
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ enum class HighlightState {
|
||||||
None,
|
None,
|
||||||
Highlighted,
|
Highlighted,
|
||||||
NewMessage,
|
NewMessage,
|
||||||
Notification,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QString qS(const std::string &string)
|
inline QString qS(const std::string &string)
|
||||||
|
|
|
@ -413,8 +413,6 @@ void TwitchChannel::setLive(bool newLiveStatus)
|
||||||
}
|
}
|
||||||
auto live = makeSystemMessage(this->getName() + " is live");
|
auto live = makeSystemMessage(this->getName() + " is live");
|
||||||
this->addMessage(live);
|
this->addMessage(live);
|
||||||
this->tabHighlightRequested.invoke(
|
|
||||||
HighlightState::Notification);
|
|
||||||
} else {
|
} else {
|
||||||
auto offline =
|
auto offline =
|
||||||
makeSystemMessage(this->getName() + " is offline");
|
makeSystemMessage(this->getName() + " is offline");
|
||||||
|
|
|
@ -66,7 +66,7 @@ public:
|
||||||
const QString &subscriptionUrl();
|
const QString &subscriptionUrl();
|
||||||
const QString &channelUrl();
|
const QString &channelUrl();
|
||||||
const QString &popoutPlayerUrl();
|
const QString &popoutPlayerUrl();
|
||||||
bool isLive() const;
|
virtual bool isLive() const override;
|
||||||
QString roomId() const;
|
QString roomId() const;
|
||||||
AccessGuard<const RoomModes> accessRoomModes() const;
|
AccessGuard<const RoomModes> accessRoomModes() const;
|
||||||
AccessGuard<const StreamStatus> accessStreamStatus() const;
|
AccessGuard<const StreamStatus> accessStreamStatus() const;
|
||||||
|
|
|
@ -105,10 +105,6 @@ void Theme::actuallyUpdate(double hue, double multiplier)
|
||||||
QColor("#000"),
|
QColor("#000"),
|
||||||
{QColor("#b4d7ff"), QColor("#b4d7ff"), QColor("#b4d7ff")},
|
{QColor("#b4d7ff"), QColor("#b4d7ff"), QColor("#b4d7ff")},
|
||||||
{QColor("#00aeef"), QColor("#00aeef"), QColor("#00aeef")}};
|
{QColor("#00aeef"), QColor("#00aeef"), QColor("#00aeef")}};
|
||||||
this->tabs.notified = {
|
|
||||||
fg,
|
|
||||||
{QColor("#fff"), QColor("#fff"), QColor("#fff")},
|
|
||||||
{QColor("#F824A8"), QColor("#F824A8"), QColor("#F824A8")}};
|
|
||||||
} else {
|
} else {
|
||||||
this->tabs.regular = {
|
this->tabs.regular = {
|
||||||
QColor("#aaa"),
|
QColor("#aaa"),
|
||||||
|
@ -127,10 +123,6 @@ void Theme::actuallyUpdate(double hue, double multiplier)
|
||||||
QColor("#fff"),
|
QColor("#fff"),
|
||||||
{QColor("#555555"), QColor("#555555"), QColor("#555555")},
|
{QColor("#555555"), QColor("#555555"), QColor("#555555")},
|
||||||
{QColor("#00aeef"), QColor("#00aeef"), QColor("#00aeef")}};
|
{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;
|
this->splits.input.focusedLine = highlighted;
|
||||||
|
|
|
@ -50,7 +50,6 @@ public:
|
||||||
TabColors newMessage;
|
TabColors newMessage;
|
||||||
TabColors highlighted;
|
TabColors highlighted;
|
||||||
TabColors selected;
|
TabColors selected;
|
||||||
TabColors notified;
|
|
||||||
QColor border;
|
QColor border;
|
||||||
QColor bottomLine;
|
QColor bottomLine;
|
||||||
} tabs;
|
} tabs;
|
||||||
|
|
|
@ -555,7 +555,10 @@ void ChannelView::setChannel(ChannelPtr newChannel)
|
||||||
TwitchChannel *tc = dynamic_cast<TwitchChannel *>(newChannel.get());
|
TwitchChannel *tc = dynamic_cast<TwitchChannel *>(newChannel.get());
|
||||||
if (tc != nullptr) {
|
if (tc != nullptr) {
|
||||||
tc->tabHighlightRequested.connect([this](HighlightState state) {
|
tc->tabHighlightRequested.connect([this](HighlightState state) {
|
||||||
this->tabHighlightRequested.invoke(HighlightState::Notification);
|
this->tabHighlightRequested.invoke(state);
|
||||||
|
});
|
||||||
|
tc->liveStatusChanged.connect([this]() {
|
||||||
|
this->liveStatusChanged.invoke(); //
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@ public:
|
||||||
pajlada::Signals::Signal<QMouseEvent *> mouseDown;
|
pajlada::Signals::Signal<QMouseEvent *> mouseDown;
|
||||||
pajlada::Signals::NoArgSignal selectionChanged;
|
pajlada::Signals::NoArgSignal selectionChanged;
|
||||||
pajlada::Signals::Signal<HighlightState> tabHighlightRequested;
|
pajlada::Signals::Signal<HighlightState> tabHighlightRequested;
|
||||||
|
pajlada::Signals::NoArgSignal liveStatusChanged;
|
||||||
pajlada::Signals::Signal<const Link &> linkClicked;
|
pajlada::Signals::Signal<const Link &> linkClicked;
|
||||||
pajlada::Signals::Signal<QString> joinToChannel;
|
pajlada::Signals::Signal<QString> joinToChannel;
|
||||||
|
|
||||||
|
|
|
@ -168,13 +168,20 @@ void NotebookTab::setSelected(bool value)
|
||||||
this->update();
|
this->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NotebookTab::setLive(bool isLive)
|
||||||
|
{
|
||||||
|
if (this->isLive_ != isLive) {
|
||||||
|
this->isLive_ = isLive;
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NotebookTab::setHighlightState(HighlightState newHighlightStyle)
|
void NotebookTab::setHighlightState(HighlightState newHighlightStyle)
|
||||||
{
|
{
|
||||||
if (this->isSelected() || !this->highlightEnabled_) {
|
if (this->isSelected() || !this->highlightEnabled_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this->highlightState_ != HighlightState::Highlighted &&
|
if (this->highlightState_ != HighlightState::Highlighted) {
|
||||||
this->highlightState_ != HighlightState::Notification) {
|
|
||||||
this->highlightState_ = newHighlightStyle;
|
this->highlightState_ = newHighlightStyle;
|
||||||
|
|
||||||
this->update();
|
this->update();
|
||||||
|
@ -252,8 +259,6 @@ void NotebookTab::paintEvent(QPaintEvent *)
|
||||||
colors = this->theme->tabs.selected;
|
colors = this->theme->tabs.selected;
|
||||||
} else if (this->highlightState_ == HighlightState::Highlighted) {
|
} else if (this->highlightState_ == HighlightState::Highlighted) {
|
||||||
colors = this->theme->tabs.highlighted;
|
colors = this->theme->tabs.highlighted;
|
||||||
} else if (this->highlightState_ == HighlightState::Notification) {
|
|
||||||
colors = this->theme->tabs.notified;
|
|
||||||
} else if (this->highlightState_ == HighlightState::NewMessage) {
|
} else if (this->highlightState_ == HighlightState::NewMessage) {
|
||||||
colors = this->theme->tabs.newMessage;
|
colors = this->theme->tabs.newMessage;
|
||||||
} else {
|
} else {
|
||||||
|
@ -297,6 +302,20 @@ void NotebookTab::paintEvent(QPaintEvent *)
|
||||||
? colors.line.hover
|
? colors.line.hover
|
||||||
: (windowFocused ? colors.line.regular : colors.line.unfocused));
|
: (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
|
// set the pen color
|
||||||
painter.setPen(colors.text);
|
painter.setPen(colors.text);
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ public:
|
||||||
bool isSelected() const;
|
bool isSelected() const;
|
||||||
void setSelected(bool value);
|
void setSelected(bool value);
|
||||||
|
|
||||||
|
void setLive(bool isLive);
|
||||||
void setHighlightState(HighlightState style);
|
void setHighlightState(HighlightState style);
|
||||||
void setHighlightsEnabled(const bool &newVal);
|
void setHighlightsEnabled(const bool &newVal);
|
||||||
bool hasHighlightsEnabled() const;
|
bool hasHighlightsEnabled() const;
|
||||||
|
@ -88,6 +89,8 @@ private:
|
||||||
bool highlightEnabled_ = true;
|
bool highlightEnabled_ = true;
|
||||||
QAction *highlightNewMessagesAction_;
|
QAction *highlightNewMessagesAction_;
|
||||||
|
|
||||||
|
bool isLive_{};
|
||||||
|
|
||||||
QMenu menu_;
|
QMenu menu_;
|
||||||
|
|
||||||
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
|
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
|
||||||
|
|
|
@ -290,7 +290,7 @@ void Split::showChangeChannelPopup(const char *dialogTitle, bool empty,
|
||||||
if (dialog->hasSeletedChannel()) {
|
if (dialog->hasSeletedChannel()) {
|
||||||
this->setChannel(dialog->getSelectedChannel());
|
this->setChannel(dialog->getSelectedChannel());
|
||||||
if (this->isInContainer()) {
|
if (this->isInContainer()) {
|
||||||
this->container_->refreshTabTitle();
|
this->container_->refreshTab();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ void SplitContainer::setTab(NotebookTab *_tab)
|
||||||
|
|
||||||
this->tab_->page = this;
|
this->tab_->page = this;
|
||||||
|
|
||||||
this->refreshTabTitle();
|
this->refreshTab();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitContainer::hideResizeHandles()
|
void SplitContainer::hideResizeHandles()
|
||||||
|
@ -177,7 +177,7 @@ void SplitContainer::addSplit(Split *split)
|
||||||
this->unsetCursor();
|
this->unsetCursor();
|
||||||
this->splits_.push_back(split);
|
this->splits_.push_back(split);
|
||||||
|
|
||||||
this->refreshTabTitle();
|
this->refreshTab();
|
||||||
|
|
||||||
split->getChannelView().tabHighlightRequested.connect(
|
split->getChannelView().tabHighlightRequested.connect(
|
||||||
[this](HighlightState state) {
|
[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); });
|
split->focused.connect([this, split] { this->setSelected(split); });
|
||||||
|
|
||||||
this->layout();
|
this->layout();
|
||||||
|
@ -228,7 +232,7 @@ SplitContainer::Position SplitContainer::releaseSplit(Split *split)
|
||||||
this->splits_.front()->giveFocus(Qt::MouseFocusReason);
|
this->splits_.front()->giveFocus(Qt::MouseFocusReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->refreshTabTitle();
|
this->refreshTab();
|
||||||
|
|
||||||
// fourtf: really bad
|
// fourtf: really bad
|
||||||
split->getChannelView().tabHighlightRequested.disconnectAll();
|
split->getChannelView().tabHighlightRequested.disconnectAll();
|
||||||
|
@ -568,34 +572,10 @@ void SplitContainer::focusInEvent(QFocusEvent *)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitContainer::refreshTabTitle()
|
void SplitContainer::refreshTab()
|
||||||
{
|
{
|
||||||
if (this->tab_ == nullptr) {
|
this->refreshTabTitle();
|
||||||
return;
|
this->refreshTabLiveStatus();
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SplitContainer::getSplitCount()
|
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
|
// Node
|
||||||
//
|
//
|
||||||
|
|
|
@ -171,7 +171,7 @@ private:
|
||||||
public:
|
public:
|
||||||
SplitContainer(Notebook *parent);
|
SplitContainer(Notebook *parent);
|
||||||
|
|
||||||
Split* appendNewSplit(bool openChannelNameDialog);
|
Split *appendNewSplit(bool openChannelNameDialog);
|
||||||
void appendSplit(Split *split);
|
void appendSplit(Split *split);
|
||||||
void insertSplit(Split *split, const Position &position);
|
void insertSplit(Split *split, const Position &position);
|
||||||
void insertSplit(Split *split, Direction direction, Split *relativeTo);
|
void insertSplit(Split *split, Direction direction, Split *relativeTo);
|
||||||
|
@ -186,7 +186,9 @@ public:
|
||||||
|
|
||||||
int getSplitCount();
|
int getSplitCount();
|
||||||
const std::vector<Split *> getSplits() const;
|
const std::vector<Split *> getSplits() const;
|
||||||
void refreshTabTitle();
|
|
||||||
|
void refreshTab();
|
||||||
|
|
||||||
NotebookTab *getTab() const;
|
NotebookTab *getTab() const;
|
||||||
Node *getBaseNode();
|
Node *getBaseNode();
|
||||||
|
|
||||||
|
@ -221,6 +223,9 @@ private:
|
||||||
void decodeNodeRecusively(QJsonObject &obj, Node *node);
|
void decodeNodeRecusively(QJsonObject &obj, Node *node);
|
||||||
Split *getTopRightSplit(Node &node);
|
Split *getTopRightSplit(Node &node);
|
||||||
|
|
||||||
|
void refreshTabTitle();
|
||||||
|
void refreshTabLiveStatus();
|
||||||
|
|
||||||
struct DropRegion {
|
struct DropRegion {
|
||||||
QRect rect;
|
QRect rect;
|
||||||
std::pair<int, int> position;
|
std::pair<int, int> position;
|
||||||
|
|
Loading…
Reference in a new issue