/live split for channels going live (#1998)

Co-authored-by: 23rd <23rd@vivaldi.net>
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
apa420
2021-05-09 16:17:04 +02:00
committed by GitHub
parent d96f4575ba
commit dcd65b5978
14 changed files with 104 additions and 12 deletions
+2
View File
@@ -2,12 +2,14 @@
## Unversioned ## Unversioned
- Major: New split for channels going live! /live. (#1797)
- Minor: Hosting messages are now clickable. (#2655) - Minor: Hosting messages are now clickable. (#2655)
- Minor: Messages held by automod are now shown to the user. (#2626) - Minor: Messages held by automod are now shown to the user. (#2626)
- Bugfix: Strip newlines from stream titles to prevent text going off of split header (#2755) - Bugfix: Strip newlines from stream titles to prevent text going off of split header (#2755)
- Bugfix: Automod messages now work properly again. (#2682) - Bugfix: Automod messages now work properly again. (#2682)
- Bugfix: `Login expired` message no longer highlights all tabs. (#2735) - Bugfix: `Login expired` message no longer highlights all tabs. (#2735)
- Bugfix: Fix a deadlock that would occur during user badge loading. (#1704, #2756) - Bugfix: Fix a deadlock that would occur during user badge loading. (#1704, #2756)
- Bugfix: Tabbing in `Select a channel to open` is now consistent. (#1797)
## 2.3.1 ## 2.3.1
+1
View File
@@ -36,6 +36,7 @@ public:
TwitchWhispers, TwitchWhispers,
TwitchWatching, TwitchWatching,
TwitchMentions, TwitchMentions,
TwitchLive,
TwitchEnd, TwitchEnd,
Irc, Irc,
Misc Misc
@@ -6,6 +6,7 @@
#include "common/QLogging.hpp" #include "common/QLogging.hpp"
#include "controllers/notifications/NotificationModel.hpp" #include "controllers/notifications/NotificationModel.hpp"
#include "providers/twitch/TwitchIrcServer.hpp" #include "providers/twitch/TwitchIrcServer.hpp"
#include "providers/twitch/TwitchMessageBuilder.hpp"
#include "providers/twitch/api/Helix.hpp" #include "providers/twitch/api/Helix.hpp"
#include "singletons/Toasts.hpp" #include "singletons/Toasts.hpp"
#include "singletons/WindowManager.hpp" #include "singletons/WindowManager.hpp"
@@ -185,6 +186,9 @@ void NotificationController::getFakeTwitchChannelLiveStatus(
{ {
getApp()->windows->sendAlert(); getApp()->windows->sendAlert();
} }
MessageBuilder builder;
TwitchMessageBuilder::liveMessage(channelName, &builder);
getApp()->twitch2->liveChannel->addMessage(builder.release());
// Indicate that we have pushed notifications for this stream // Indicate that we have pushed notifications for this stream
fakeTwitchChannels.push_back(channelName); fakeTwitchChannels.push_back(channelName);
+15
View File
@@ -563,10 +563,25 @@ void TwitchChannel::setLive(bool newLiveStatus)
getApp()->windows->sendAlert(); getApp()->windows->sendAlert();
} }
} }
// Channel live message
MessageBuilder builder; MessageBuilder builder;
TwitchMessageBuilder::liveSystemMessage(this->getDisplayName(), TwitchMessageBuilder::liveSystemMessage(this->getDisplayName(),
&builder); &builder);
this->addMessage(builder.release()); this->addMessage(builder.release());
// Message in /live channel
MessageBuilder builder2;
TwitchMessageBuilder::liveMessage(this->getDisplayName(),
&builder2);
getApp()->twitch2->liveChannel->addMessage(builder2.release());
// Notify on all channels with a ping sound
if (getSettings()->notificationOnAnyChannel &&
!(isInStreamerMode() &&
getSettings()->streamerModeSuppressLiveNotifications))
{
getApp()->notifications->playSound();
}
} }
else else
{ {
+7
View File
@@ -28,6 +28,7 @@ TwitchIrcServer::TwitchIrcServer()
: whispersChannel(new Channel("/whispers", Channel::Type::TwitchWhispers)) : whispersChannel(new Channel("/whispers", Channel::Type::TwitchWhispers))
, mentionsChannel(new Channel("/mentions", Channel::Type::TwitchMentions)) , mentionsChannel(new Channel("/mentions", Channel::Type::TwitchMentions))
, watchingChannel(Channel::getEmpty(), Channel::Type::TwitchWatching) , watchingChannel(Channel::getEmpty(), Channel::Type::TwitchWatching)
, liveChannel(new Channel("/live", Channel::Type::TwitchLive))
{ {
this->initializeIrc(); this->initializeIrc();
@@ -257,6 +258,11 @@ std::shared_ptr<Channel> TwitchIrcServer::getCustomChannel(
return this->mentionsChannel; return this->mentionsChannel;
} }
if (channelName == "/live")
{
return this->liveChannel;
}
if (channelName == "$$$") if (channelName == "$$$")
{ {
static auto channel = static auto channel =
@@ -289,6 +295,7 @@ void TwitchIrcServer::forEachChannelAndSpecialChannels(
func(this->whispersChannel); func(this->whispersChannel);
func(this->mentionsChannel); func(this->mentionsChannel);
func(this->liveChannel);
} }
std::shared_ptr<Channel> TwitchIrcServer::getChannelOrEmptyByID( std::shared_ptr<Channel> TwitchIrcServer::getChannelOrEmptyByID(
+1
View File
@@ -35,6 +35,7 @@ public:
const ChannelPtr whispersChannel; const ChannelPtr whispersChannel;
const ChannelPtr mentionsChannel; const ChannelPtr mentionsChannel;
const ChannelPtr liveChannel;
IndirectChannel watchingChannel; IndirectChannel watchingChannel;
PubSub *pubsub; PubSub *pubsub;
@@ -1302,6 +1302,18 @@ void TwitchMessageBuilder::appendChannelPointRewardMessage(
builder->message().flags.set(MessageFlag::RedeemedChannelPointReward); builder->message().flags.set(MessageFlag::RedeemedChannelPointReward);
} }
void TwitchMessageBuilder::liveMessage(const QString &channelName,
MessageBuilder *builder)
{
builder->emplace<TimestampElement>();
builder
->emplace<TextElement>(channelName, MessageElementFlag::Username,
MessageColor::Text, FontStyle::ChatMediumBold)
->setLink({Link::UserInfo, channelName});
builder->emplace<TextElement>("is live!", MessageElementFlag::Text,
MessageColor::Text);
}
void TwitchMessageBuilder::liveSystemMessage(const QString &channelName, void TwitchMessageBuilder::liveSystemMessage(const QString &channelName,
MessageBuilder *builder) MessageBuilder *builder)
{ {
@@ -52,6 +52,12 @@ public:
static void appendChannelPointRewardMessage( static void appendChannelPointRewardMessage(
const ChannelPointReward &reward, MessageBuilder *builder); const ChannelPointReward &reward, MessageBuilder *builder);
// Message in the /live chat for channel going live
static void liveMessage(const QString &channelName,
MessageBuilder *builder);
// Messages in normal chat for channel stuff
static void liveSystemMessage(const QString &channelName, static void liveSystemMessage(const QString &channelName,
MessageBuilder *builder); MessageBuilder *builder);
static void offlineSystemMessage(const QString &channelName, static void offlineSystemMessage(const QString &channelName,
+2
View File
@@ -300,6 +300,8 @@ public:
false}; false};
QStringSetting notificationPathSound = {"/notifications/highlightSoundPath", QStringSetting notificationPathSound = {"/notifications/highlightSoundPath",
"qrc:/sounds/ping3.wav"}; "qrc:/sounds/ping3.wav"};
BoolSetting notificationOnAnyChannel = {"/notifications/onAnyChannel",
false};
BoolSetting notificationToast = {"/notifications/enableToast", false}; BoolSetting notificationToast = {"/notifications/enableToast", false};
IntSetting openFromToast = {"/notifications/openFromToast", IntSetting openFromToast = {"/notifications/openFromToast",
+8
View File
@@ -559,6 +559,10 @@ void WindowManager::encodeChannel(IndirectChannel channel, QJsonObject &obj)
obj.insert("type", "whispers"); obj.insert("type", "whispers");
} }
break; break;
case Channel::Type::TwitchLive: {
obj.insert("type", "live");
}
break;
case Channel::Type::Irc: { case Channel::Type::Irc: {
if (auto ircChannel = if (auto ircChannel =
dynamic_cast<IrcChannel *>(channel.get().get())) dynamic_cast<IrcChannel *>(channel.get().get()))
@@ -608,6 +612,10 @@ IndirectChannel WindowManager::decodeChannel(const SplitDescriptor &descriptor)
{ {
return app->twitch.server->whispersChannel; return app->twitch.server->whispersChannel;
} }
else if (descriptor.type_ == "live")
{
return app->twitch.server->liveChannel;
}
else if (descriptor.type_ == "irc") else if (descriptor.type_ == "irc")
{ {
return Irc::instance().getOrAddChannel(descriptor.server_, return Irc::instance().getOrAddChannel(descriptor.server_,
+38 -10
View File
@@ -119,17 +119,31 @@ SelectChannelDialog::SelectChannelDialog(QWidget *parent)
watching_lbl->setVisible(enabled); watching_lbl->setVisible(enabled);
}); });
// live_btn
auto live_btn =
vbox.emplace<QRadioButton>("Live").assign(&this->ui_.twitch.live);
auto live_lbl =
vbox.emplace<QLabel>("Shows when channels go live.").hidden();
live_lbl->setWordWrap(true);
live_btn->installEventFilter(&this->tabFilter_);
QObject::connect(live_btn.getElement(), &QRadioButton::toggled,
[=](bool enabled) mutable {
live_lbl->setVisible(enabled);
});
vbox->addStretch(1); vbox->addStretch(1);
// tabbing order // tabbing order
QWidget::setTabOrder(watching_btn.getElement(), QWidget::setTabOrder(live_btn.getElement(), channel_btn.getElement());
channel_btn.getElement());
QWidget::setTabOrder(channel_btn.getElement(), QWidget::setTabOrder(channel_btn.getElement(),
whispers_btn.getElement()); whispers_btn.getElement());
QWidget::setTabOrder(whispers_btn.getElement(), QWidget::setTabOrder(whispers_btn.getElement(),
mentions_btn.getElement()); mentions_btn.getElement());
QWidget::setTabOrder(mentions_btn.getElement(), QWidget::setTabOrder(mentions_btn.getElement(),
watching_btn.getElement()); watching_btn.getElement());
QWidget::setTabOrder(watching_btn.getElement(), live_btn.getElement());
// tab // tab
auto tab = notebook->addPage(obj.getElement()); auto tab = notebook->addPage(obj.getElement());
@@ -294,6 +308,11 @@ void SelectChannelDialog::setSelectedChannel(IndirectChannel _channel)
this->ui_.twitch.whispers->setFocus(); this->ui_.twitch.whispers->setFocus();
} }
break; break;
case Channel::Type::TwitchLive: {
this->ui_.notebook->selectIndex(TAB_TWITCH);
this->ui_.twitch.live->setFocus();
}
break;
case Channel::Type::Irc: { case Channel::Type::Irc: {
this->ui_.notebook->selectIndex(TAB_IRC); this->ui_.notebook->selectIndex(TAB_IRC);
this->ui_.irc.channel->setText(_channel.get()->getName()); this->ui_.irc.channel->setText(_channel.get()->getName());
@@ -357,6 +376,10 @@ IndirectChannel SelectChannelDialog::getSelectedChannel() const
{ {
return app->twitch.server->whispersChannel; return app->twitch.server->whispersChannel;
} }
else if (this->ui_.twitch.live->isChecked())
{
return app->twitch.server->liveChannel;
}
} }
break; break;
case TAB_IRC: { case TAB_IRC: {
@@ -417,15 +440,22 @@ bool SelectChannelDialog::EventFilter::eventFilter(QObject *watched,
event_key->key() == Qt::Key_Down) && event_key->key() == Qt::Key_Down) &&
event_key->modifiers() == Qt::NoModifier) event_key->modifiers() == Qt::NoModifier)
{ {
// Tab has been pressed, focus next entry in list
if (widget == this->dialog->ui_.twitch.channelName) if (widget == this->dialog->ui_.twitch.channelName)
{ {
// Special case for when current selection is the "Channel" entry's edit box since the Edit box actually has the focus
this->dialog->ui_.twitch.whispers->setFocus(); this->dialog->ui_.twitch.whispers->setFocus();
return true; return true;
} }
else else if (widget == this->dialog->ui_.twitch.live)
{ {
widget->nextInFocusChain()->setFocus(); // Special case for when current selection is "Live" (the last entry in the list), next wrap is Channel, but we need to select its edit box
this->dialog->ui_.twitch.channel->setFocus();
return true;
} }
widget->nextInFocusChain()->setFocus();
return true; return true;
} }
else if (((event_key->key() == Qt::Key_Tab || else if (((event_key->key() == Qt::Key_Tab ||
@@ -434,14 +464,12 @@ bool SelectChannelDialog::EventFilter::eventFilter(QObject *watched,
((event_key->key() == Qt::Key_Up) && ((event_key->key() == Qt::Key_Up) &&
event_key->modifiers() == Qt::NoModifier)) event_key->modifiers() == Qt::NoModifier))
{ {
// Shift+Tab has been pressed, focus previous entry in list
if (widget == this->dialog->ui_.twitch.channelName) if (widget == this->dialog->ui_.twitch.channelName)
{ {
this->dialog->ui_.twitch.watching->setFocus(); // Special case for when current selection is the "Channel" entry's edit box since the Edit box actually has the focus
return true; this->dialog->ui_.twitch.live->setFocus();
}
else if (widget == this->dialog->ui_.twitch.whispers)
{
this->dialog->ui_.twitch.channel->setFocus();
return true; return true;
} }
@@ -49,6 +49,7 @@ private:
QRadioButton *whispers; QRadioButton *whispers;
QRadioButton *mentions; QRadioButton *mentions;
QRadioButton *watching; QRadioButton *watching;
QRadioButton *live;
} twitch; } twitch;
struct { struct {
QLineEdit *channel; QLineEdit *channel;
+2 -1
View File
@@ -994,7 +994,8 @@ MessageElementFlags ChannelView::getFlags() const
{ {
flags.set(MessageElementFlag::ModeratorTools); flags.set(MessageElementFlag::ModeratorTools);
} }
if (this->underlyingChannel_ == app->twitch.server->mentionsChannel) if (this->underlyingChannel_ == app->twitch.server->mentionsChannel ||
this->underlyingChannel_ == app->twitch.server->liveChannel)
{ {
flags.set(MessageElementFlag::ChannelName); flags.set(MessageElementFlag::ChannelName);
flags.unset(MessageElementFlag::ChannelPointReward); flags.unset(MessageElementFlag::ChannelPointReward);
@@ -35,8 +35,12 @@ NotificationPage::NotificationPage()
settings.append(this->createCheckBox( settings.append(this->createCheckBox(
"Flash taskbar", getSettings()->notificationFlashTaskbar)); "Flash taskbar", getSettings()->notificationFlashTaskbar));
settings.append(
this->createCheckBox("Play sound for selected channels",
getSettings()->notificationPlaySound));
settings.append(this->createCheckBox( settings.append(this->createCheckBox(
"Play sound", getSettings()->notificationPlaySound)); "Play sound for any channel going live",
getSettings()->notificationOnAnyChannel));
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
settings.append(this->createCheckBox( settings.append(this->createCheckBox(
"Show notification", getSettings()->notificationToast)); "Show notification", getSettings()->notificationToast));