2018-06-26 14:09:39 +02:00
# include "widgets/Window.hpp"
2018-04-27 22:11:19 +02:00
2018-06-26 14:09:39 +02:00
# include "Application.hpp"
2019-09-13 19:26:52 +02:00
# include "common/Credentials.hpp"
2019-09-15 15:45:04 +02:00
# include "common/Modes.hpp"
2018-06-26 15:33:51 +02:00
# include "common/Version.hpp"
2018-06-26 14:09:39 +02:00
# include "controllers/accounts/AccountController.hpp"
2019-09-15 13:02:02 +02:00
# include "providers/twitch/TwitchIrcServer.hpp"
2018-06-28 19:46:45 +02:00
# include "singletons/Settings.hpp"
2018-06-28 20:03:04 +02:00
# include "singletons/Theme.hpp"
2018-07-05 11:42:40 +02:00
# include "singletons/Updates.hpp"
2018-06-26 14:09:39 +02:00
# include "singletons/WindowManager.hpp"
2018-07-05 12:52:36 +02:00
# include "util/InitUpdateButton.hpp"
2018-11-25 21:14:42 +01:00
# include "util/Shortcut.hpp"
2019-09-01 14:13:44 +02:00
# include "widgets/AccountSwitchPopup.hpp"
2018-06-26 14:09:39 +02:00
# include "widgets/Notebook.hpp"
2018-06-26 15:11:45 +02:00
# include "widgets/dialogs/SettingsDialog.hpp"
2018-07-05 16:04:39 +02:00
# include "widgets/dialogs/UpdateDialog.hpp"
2018-06-26 15:11:45 +02:00
# include "widgets/dialogs/WelcomeDialog.hpp"
2020-08-13 19:25:51 +02:00
# include "widgets/dialogs/switcher/QuickSwitcherPopup.hpp"
2018-08-11 22:23:06 +02:00
# include "widgets/helper/EffectLabel.hpp"
2018-10-09 19:43:29 +02:00
# include "widgets/helper/NotebookTab.hpp"
2018-08-11 22:23:06 +02:00
# include "widgets/helper/TitlebarButton.hpp"
2018-10-09 19:43:29 +02:00
# include "widgets/splits/ClosedSplits.hpp"
2018-06-26 15:33:51 +02:00
# include "widgets/splits/Split.hpp"
2018-08-11 22:23:06 +02:00
# include "widgets/splits/SplitContainer.hpp"
2016-12-29 17:31:07 +01:00
2021-05-20 14:21:41 +02:00
# ifndef NDEBUG
2020-08-08 15:37:22 +02:00
# include <rapidjson / document.h>
# include "providers / twitch / PubsubClient.hpp"
2019-09-08 19:40:30 +02:00
# include "util / SampleCheerMessages.hpp"
2019-12-29 15:45:52 +01:00
# include "util / SampleLinks.hpp"
2019-09-08 19:40:30 +02:00
# endif
2018-04-10 02:02:49 +02:00
# include <QApplication>
2018-06-23 22:49:07 +02:00
# include <QDesktopServices>
2018-04-25 14:49:30 +02:00
# include <QHeaderView>
2019-09-22 16:16:08 +02:00
# include <QMenuBar>
2017-01-18 04:52:47 +01:00
# include <QPalette>
2017-05-27 15:40:42 +02:00
# include <QShortcut>
2018-04-26 18:10:26 +02:00
# include <QStandardItemModel>
2019-09-22 16:16:08 +02:00
# include <QVBoxLayout>
2018-04-25 14:49:30 +02:00
2017-04-14 17:52:22 +02:00
namespace chatterino {
2017-01-18 21:30:23 +01:00
2018-08-11 22:23:06 +02:00
Window : : Window ( WindowType type )
2019-09-08 21:45:46 +02:00
: BaseWindow ( BaseWindow : : EnableCustomFrame )
2018-07-06 17:02:26 +02:00
, type_ ( type )
2018-08-11 22:23:06 +02:00
, notebook_ ( new SplitNotebook ( this ) )
2016-12-29 17:31:07 +01:00
{
2018-07-06 17:02:26 +02:00
this - > addCustomTitlebarButtons ( ) ;
this - > addDebugStuff ( ) ;
this - > addShortcuts ( ) ;
this - > addLayout ( ) ;
2018-04-27 22:11:19 +02:00
2019-06-09 16:13:06 +02:00
# ifdef Q_OS_MACOS
this - > addMenuBar ( ) ;
# endif
2018-09-04 22:05:27 +02:00
this - > signalHolder_ . managedConnect (
2020-11-08 12:02:19 +01:00
getApp ( ) - > accounts - > twitch . currentUserChanged , [ this ] {
this - > onAccountSelected ( ) ;
} ) ;
2018-07-06 17:02:26 +02:00
this - > onAccountSelected ( ) ;
2018-05-25 18:23:13 +02:00
2018-10-21 13:43:02 +02:00
if ( type = = WindowType : : Main )
{
2018-11-21 21:37:41 +01:00
this - > resize ( int ( 600 * this - > scale ( ) ) , int ( 500 * this - > scale ( ) ) ) ;
2018-10-21 13:43:02 +02:00
}
else
{
2018-11-21 21:37:41 +01:00
this - > resize ( int ( 300 * this - > scale ( ) ) , int ( 500 * this - > scale ( ) ) ) ;
2018-07-06 17:02:26 +02:00
}
2021-05-30 12:22:26 +02:00
if ( type = = WindowType : : Main | | type = = WindowType : : Popup )
{
getSettings ( ) - > tabDirection . connect ( [ this ] ( int val ) {
this - > notebook_ - > setTabDirection ( NotebookTabDirection ( val ) ) ;
} ) ;
}
2018-07-06 17:02:26 +02:00
}
2018-08-11 22:23:06 +02:00
WindowType Window : : getType ( )
2018-07-06 17:02:26 +02:00
{
return this - > type_ ;
}
SplitNotebook & Window : : getNotebook ( )
{
2018-08-11 22:23:06 +02:00
return * this - > notebook_ ;
2018-07-06 17:02:26 +02:00
}
bool Window : : event ( QEvent * event )
{
2018-10-21 13:43:02 +02:00
switch ( event - > type ( ) )
{
2018-07-06 17:02:26 +02:00
case QEvent : : WindowActivate :
break ;
2019-09-26 00:51:05 +02:00
case QEvent : : WindowDeactivate : {
2018-08-11 22:23:06 +02:00
auto page = this - > notebook_ - > getOrAddSelectedPage ( ) ;
2018-07-06 17:02:26 +02:00
2018-10-21 13:43:02 +02:00
if ( page ! = nullptr )
{
2018-07-06 17:02:26 +02:00
std : : vector < Split * > splits = page - > getSplits ( ) ;
2018-10-21 13:43:02 +02:00
for ( Split * split : splits )
{
2018-07-06 17:02:26 +02:00
split - > updateLastReadMessage ( ) ;
}
2018-06-06 20:11:07 +02:00
}
2018-05-25 18:23:13 +02:00
2018-08-06 21:17:03 +02:00
if ( SplitContainer * container =
2018-10-21 13:43:02 +02:00
dynamic_cast < SplitContainer * > ( page ) )
{
2018-07-06 17:02:26 +02:00
container - > hideResizeHandles ( ) ;
2018-06-06 20:11:07 +02:00
}
2018-10-21 13:43:02 +02:00
}
break ;
2018-07-06 17:02:26 +02:00
default : ;
2019-09-13 19:26:52 +02:00
}
2018-07-06 17:02:26 +02:00
return BaseWindow : : event ( event ) ;
}
void Window : : closeEvent ( QCloseEvent * )
{
2018-10-21 13:43:02 +02:00
if ( this - > type_ = = WindowType : : Main )
{
2018-07-06 17:02:26 +02:00
auto app = getApp ( ) ;
app - > windows - > save ( ) ;
app - > windows - > closeAll ( ) ;
2018-01-15 01:35:35 +01:00
}
2018-07-06 17:02:26 +02:00
this - > closed . invoke ( ) ;
2018-10-21 13:43:02 +02:00
if ( this - > type_ = = WindowType : : Main )
{
2018-07-06 17:02:26 +02:00
QApplication : : exit ( ) ;
2018-04-06 23:31:34 +02:00
}
2018-07-06 17:02:26 +02:00
}
2018-04-06 23:31:34 +02:00
2018-07-06 17:02:26 +02:00
void Window : : addLayout ( )
{
2017-04-12 17:46:44 +02:00
QVBoxLayout * layout = new QVBoxLayout ( this ) ;
2018-08-11 22:23:06 +02:00
layout - > addWidget ( this - > notebook_ ) ;
2018-01-15 01:35:35 +01:00
this - > getLayoutContainer ( ) - > setLayout ( layout ) ;
2017-04-12 17:46:44 +02:00
// set margin
layout - > setMargin ( 0 ) ;
2016-12-30 12:20:26 +01:00
2018-08-11 22:23:06 +02:00
this - > notebook_ - > setAllowUserTabManagement ( true ) ;
this - > notebook_ - > setShowAddButton ( true ) ;
2018-07-06 17:02:26 +02:00
}
2018-01-06 20:58:56 +01:00
2018-07-06 17:02:26 +02:00
void Window : : addCustomTitlebarButtons ( )
{
2018-10-21 13:43:02 +02:00
if ( ! this - > hasCustomWindowFrame ( ) )
return ;
if ( this - > type_ ! = WindowType : : Main )
return ;
2018-07-06 17:02:26 +02:00
// settings
2020-10-31 16:42:48 +01:00
this - > addTitleBarButton ( TitleBarButtonStyle : : Settings , [ this ] {
2020-11-08 12:02:19 +01:00
getApp ( ) - > windows - > showSettingsDialog ( this ) ;
2020-10-31 16:42:48 +01:00
} ) ;
2018-06-11 15:04:54 +02:00
2018-07-06 17:02:26 +02:00
// updates
2018-08-11 22:23:06 +02:00
auto update = this - > addTitleBarButton ( TitleBarButtonStyle : : None , [ ] { } ) ;
2018-01-06 20:58:56 +01:00
2018-08-11 22:23:06 +02:00
initUpdateButton ( * update , this - > signalHolder_ ) ;
2018-01-12 19:15:21 +01:00
2018-07-06 17:02:26 +02:00
// account
this - > userLabel_ = this - > addTitleBarLabel ( [ this ] {
2018-08-06 21:17:03 +02:00
getApp ( ) - > windows - > showAccountSelectPopup ( this - > userLabel_ - > mapToGlobal (
2018-08-11 22:23:06 +02:00
this - > userLabel_ - > rect ( ) . bottomLeft ( ) ) ) ;
2018-07-06 17:02:26 +02:00
} ) ;
2018-11-21 21:37:41 +01:00
this - > userLabel_ - > setMinimumWidth ( 20 * scale ( ) ) ;
2018-07-06 17:02:26 +02:00
}
void Window : : addDebugStuff ( )
{
2021-05-20 14:21:41 +02:00
# ifndef NDEBUG
2020-09-26 14:21:46 +02:00
std : : vector < QString > cheerMessages , subMessages , miscMessages , linkMessages ,
emoteTestMessages ;
2019-09-08 19:36:26 +02:00
cheerMessages = getSampleCheerMessage ( ) ;
2019-12-29 15:45:52 +01:00
auto validLinks = getValidLinks ( ) ;
auto invalidLinks = getInvalidLinks ( ) ;
2018-01-12 19:15:21 +01:00
// clang-format off
2018-06-05 14:08:55 +02:00
subMessages . emplace_back ( R " (@badges=staff/1,broadcaster/1,turbo/1;color=#008000;display-name=ronni;emotes=;id=db25007f-7a18-43eb-9379-80131e44d633;login=ronni;mod=0;msg-id=resub;msg-param-months=6;msg-param-sub-plan=Prime;msg-param-sub-plan-name=Prime;room-id=1337;subscriber=1;system-msg=ronni \ shas \ ssubscribed \ sfor \ s6 \ smonths!;tmi-sent-ts=1507246572675;turbo=1;user-id=1337;user-type=staff :tmi.twitch.tv USERNOTICE #pajlada :Great stream -- keep it up!) " ) ;
subMessages . emplace_back ( R " (@badges=staff/1,premium/1;color=#0000FF;display-name=TWW2;emotes=;id=e9176cd8-5e22-4684-ad40-ce53c2561c5e;login=tww2;mod=0;msg-id=subgift;msg-param-months=1;msg-param-recipient-display-name=Mr_Woodchuck;msg-param-recipient-id=89614178;msg-param-recipient-name=mr_woodchuck;msg-param-sub-plan-name=House \ sof \ sNyoro~n;msg-param-sub-plan=1000;room-id=19571752;subscriber=0;system-msg=TWW2 \ sgifted \ sa \ sTier \ s1 \ ssub \ sto \ sMr_Woodchuck!;tmi-sent-ts=1521159445153;turbo=0;user-id=13405587;user-type=staff :tmi.twitch.tv USERNOTICE #pajlada) " ) ;
// hyperbolicxd gifted a sub to quote_if_nam
subMessages . emplace_back ( R " (@badges=subscriber/0,premium/1;color=#00FF7F;display-name=hyperbolicxd;emotes=;id=b20ef4fe-cba8-41d0-a371-6327651dc9cc;login=hyperbolicxd;mod=0;msg-id=subgift;msg-param-months=1;msg-param-recipient-display-name=quote_if_nam;msg-param-recipient-id=217259245;msg-param-recipient-user-name=quote_if_nam;msg-param-sender-count=1;msg-param-sub-plan-name=Channel \ sSubscription \ s(nymn_hs);msg-param-sub-plan=1000;room-id=62300805;subscriber=1;system-msg=hyperbolicxd \ sgifted \ sa \ sTier \ s1 \ ssub \ sto \ squote_if_nam! \ sThis \ sis \ stheir \ sfirst \ sGift \ sSub \ sin \ sthe \ schannel!;tmi-sent-ts=1528190938558;turbo=0;user-id=111534250;user-type= :tmi.twitch.tv USERNOTICE #pajlada) " ) ;
// first time sub
subMessages . emplace_back ( R " (@badges=subscriber/0,premium/1;color=#0000FF;display-name=byebyeheart;emotes=;id=fe390424-ab89-4c33-bb5a-53c6e5214b9f;login=byebyeheart;mod=0;msg-id=sub;msg-param-months=0;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=Prime;room-id=39298218;subscriber=0;system-msg=byebyeheart \ sjust \ ssubscribed \ swith \ sTwitch \ sPrime!;tmi-sent-ts=1528190963670;turbo=0;user-id=131956000;user-type= :tmi.twitch.tv USERNOTICE #pajlada) " ) ;
// first time sub
subMessages . emplace_back ( R " (@badges=subscriber/0,premium/1;color=;display-name=vJoeyzz;emotes=;id=b2476df5-fffe-4338-837b-380c5dd90051;login=vjoeyzz;mod=0;msg-id=sub;msg-param-months=0;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=Prime;room-id=39298218;subscriber=0;system-msg=vJoeyzz \ sjust \ ssubscribed \ swith \ sTwitch \ sPrime!;tmi-sent-ts=1528190995089;turbo=0;user-id=78945903;user-type= :tmi.twitch.tv USERNOTICE #pajlada) " ) ;
// first time sub
subMessages . emplace_back ( R " (@badges=subscriber/0,premium/1;color=;display-name=Lennydog3;emotes=;id=44feb1eb-df60-45f6-904b-7bf0d5375a41;login=lennydog3;mod=0;msg-id=sub;msg-param-months=0;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=Prime;room-id=39298218;subscriber=0;system-msg=Lennydog3 \ sjust \ ssubscribed \ swith \ sTwitch \ sPrime!;tmi-sent-ts=1528191098733;turbo=0;user-id=175759335;user-type= :tmi.twitch.tv USERNOTICE #pajlada) " ) ;
// resub with message
subMessages . emplace_back ( R " (@badges=subscriber/0,premium/1;color=#1E90FF;display-name=OscarLord;emotes=;id=376529fd-31a8-4da9-9c0d-92a9470da2cd;login=oscarlord;mod=0;msg-id=resub;msg-param-months=2;msg-param-sub-plan-name=Dakotaz;msg-param-sub-plan=1000;room-id=39298218;subscriber=1;system-msg=OscarLord \ sjust \ ssubscribed \ swith \ sa \ sTier \ s1 \ ssub. \ sOscarLord \ ssubscribed \ sfor \ s2 \ smonths \ sin \ sa \ srow!;tmi-sent-ts=1528191154801;turbo=0;user-id=162607810;user-type= :tmi.twitch.tv USERNOTICE #pajlada :Hey dk love to watch your streams keep up the good work) " ) ;
// resub with message
subMessages . emplace_back ( R " (@badges=subscriber/0,premium/1;color=;display-name=samewl;emotes=9:22-23;id=599fda87-ca1e-41f2-9af7-6a28208daf1c;login=samewl;mod=0;msg-id=resub;msg-param-months=5;msg-param-sub-plan-name=Channel \ sSubscription \ s(forsenlol);msg-param-sub-plan=Prime;room-id=22484632;subscriber=1;system-msg=samewl \ sjust \ ssubscribed \ swith \ sTwitch \ sPrime. \ ssamewl \ ssubscribed \ sfor \ s5 \ smonths \ sin \ sa \ srow!;tmi-sent-ts=1528191317948;turbo=0;user-id=70273207;user-type= :tmi.twitch.tv USERNOTICE #pajlada :lot of love sebastian <3) " ) ;
// resub without message
subMessages . emplace_back ( R " (@badges=subscriber/12;color=#CC00C2;display-name=cspice;emotes=;id=6fc4c3e0-ca61-454a-84b8-5669dee69fc9;login=cspice;mod=0;msg-id=resub;msg-param-months=12;msg-param-sub-plan-name=Channel \ sSubscription \ s(forsenlol): \ s$9.99 \ sSub;msg-param-sub-plan=2000;room-id=22484632;subscriber=1;system-msg=cspice \ sjust \ ssubscribed \ swith \ sa \ sTier \ s2 \ ssub. \ scspice \ ssubscribed \ sfor \ s12 \ smonths \ sin \ sa \ srow!;tmi-sent-ts=1528192510808;turbo=0;user-id=47894662;user-type= :tmi.twitch.tv USERNOTICE #pajlada) " ) ;
2018-06-24 16:24:40 +02:00
// display name renders strangely
miscMessages . emplace_back ( R " (@badges=;color=#00AD2B;display-name=Iamme420 \ s;emotes=;id=d47a1e4b-a3c6-4b9e-9bf1-51b8f3dbc76e;mod=0;room-id=11148817;subscriber=0;tmi-sent-ts=1529670347537;turbo=0;user-id=56422869;user-type= :iamme420!iamme420@iamme420.tmi.twitch.tv PRIVMSG #pajlada :offline chat gachiBASS) " ) ;
2019-12-01 13:32:41 +01:00
miscMessages . emplace_back ( R " (@badge-info=founder/47;badges=moderator/1,founder/0,premium/1;color=#00FF80;display-name=gempir;emotes=;flags=;id=d4514490-202e-43cb-b429-ef01a9d9c2fe;mod=1;room-id=11148817;subscriber=0;tmi-sent-ts=1575198233854;turbo=0;user-id=77829817;user-type=mod :gempir!gempir@gempir.tmi.twitch.tv PRIVMSG #pajlada :offline chat gachiBASS) " ) ;
2019-12-29 15:45:52 +01:00
// various link tests
linkMessages . emplace_back ( R " (@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should pass: ) " + getValidLinks ( ) . join ( ' ' ) ) ;
linkMessages . emplace_back ( R " (@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should NOT pass: ) " + getInvalidLinks ( ) . join ( ' ' ) ) ;
linkMessages . emplace_back ( R " (@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should technically pass but we choose not to parse them: ) " + getValidButIgnoredLinks ( ) . join ( ' ' ) ) ;
2020-08-08 15:37:22 +02:00
// channel point reward test
const char * channelRewardMessage = " { \" type \" : \" MESSAGE \" , \" data \" : { \" topic \" : \" community-points-channel-v1.11148817 \" , \" message \" : { \" type \" : \" reward-redeemed \" , \" data \" : { \" timestamp \" : \" 2020-07-13T20:19:31.430785354Z \" , \" redemption \" : { \" id \" : \" b9628798-1b4e-4122-b2a6-031658df6755 \" , \" user \" : { \" id \" : \" 91800084 \" , \" login \" : \" cranken1337 \" , \" display_name \" : \" cranken1337 \" }, \" channel_id \" : \" 11148817 \" , \" redeemed_at \" : \" 2020-07-13T20:19:31.345237005Z \" , \" reward \" : { \" id \" : \" 313969fe-cc9f-4a0a-83c6-172acbd96957 \" , \" channel_id \" : \" 11148817 \" , \" title \" : \" annoying reward pogchamp \" , \" prompt \" : \" \" , \" cost \" : 3000, \" is_user_input_required \" : true, \" is_sub_only \" : false, \" image \" : null, \" default_image \" : { \" url_1x \" : \" https://static-cdn.jtvnw.net/custom-reward-images/default-1.png \" , \" url_2x \" : \" https://static-cdn.jtvnw.net/custom-reward-images/default-2.png \" , \" url_4x \" : \" https://static-cdn.jtvnw.net/custom-reward-images/default-4.png \" }, \" background_color \" : \" #52ACEC \" , \" is_enabled \" : true, \" is_paused \" : false, \" is_in_stock \" : true, \" max_per_stream \" : { \" is_enabled \" : false, \" max_per_stream \" : 0 }, \" should_redemptions_skip_request_queue \" : false, \" template_id \" : null, \" updated_for_indicator_at \" : \" 2020-01-20T04:33:33.624956679Z \" }, \" user_input \" : \" wow, amazing reward \" , \" status \" : \" UNFULFILLED \" , \" cursor \" : \" Yjk2Mjg3OTgtMWI0ZS00MTIyLWIyYTYtMDMxNjU4ZGY2NzU1X18yMDIwLTA3LTEzVDIwOjE5OjMxLjM0NTIzNzAwNVo= \" } } } } } " ;
const char * channelRewardMessage2 = " { \" type \" : \" MESSAGE \" , \" data \" : { \" topic \" : \" community-points-channel-v1.11148817 \" , \" message \" : { \" type \" : \" reward-redeemed \" , \" data \" : { \" timestamp \" : \" 2020-07-13T20:19:31.430785354Z \" , \" redemption \" : { \" id \" : \" b9628798-1b4e-4122-b2a6-031658df6755 \" , \" user \" : { \" id \" : \" 91800084 \" , \" login \" : \" cranken1337 \" , \" display_name \" : \" cranken1337 \" }, \" channel_id \" : \" 11148817 \" , \" redeemed_at \" : \" 2020-07-13T20:19:31.345237005Z \" , \" reward \" : { \" id \" : \" 313969fe-cc9f-4a0a-83c6-172acbd96957 \" , \" channel_id \" : \" 11148817 \" , \" title \" : \" annoying reward pogchamp \" , \" prompt \" : \" \" , \" cost \" : 3000, \" is_user_input_required \" : false, \" is_sub_only \" : false, \" image \" : null, \" default_image \" : { \" url_1x \" : \" https://static-cdn.jtvnw.net/custom-reward-images/default-1.png \" , \" url_2x \" : \" https://static-cdn.jtvnw.net/custom-reward-images/default-2.png \" , \" url_4x \" : \" https://static-cdn.jtvnw.net/custom-reward-images/default-4.png \" }, \" background_color \" : \" #52ACEC \" , \" is_enabled \" : true, \" is_paused \" : false, \" is_in_stock \" : true, \" max_per_stream \" : { \" is_enabled \" : false, \" max_per_stream \" : 0 }, \" should_redemptions_skip_request_queue \" : false, \" template_id \" : null, \" updated_for_indicator_at \" : \" 2020-01-20T04:33:33.624956679Z \" }, \" status \" : \" UNFULFILLED \" , \" cursor \" : \" Yjk2Mjg3OTgtMWI0ZS00MTIyLWIyYTYtMDMxNjU4ZGY2NzU1X18yMDIwLTA3LTEzVDIwOjE5OjMxLjM0NTIzNzAwNVo= \" } } } } } " ;
const char * channelRewardIRCMessage ( R " (@badge-info=subscriber/43;badges=subscriber/42;color=#1E90FF;custom-reward-id=313969fe-cc9f-4a0a-83c6-172acbd96957;display-name=Cranken1337;emotes=;flags=;id=3cee3f27-a1d0-44d1-a606-722cebdad08b;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1594756484132;turbo=0;user-id=91800084;user-type= :cranken1337!cranken1337@cranken1337.tmi.twitch.tv PRIVMSG #pajlada :wow, amazing reward) " ) ;
2020-09-26 14:21:46 +02:00
emoteTestMessages . emplace_back ( R " (@badge-info=subscriber/3;badges=subscriber/3;color=#0000FF;display-name=Linkoping;emotes=25:40-44;flags=17-26:S.6;id=744f9c58-b180-4f46-bd9e-b515b5ef75c1;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1566335866017;turbo=0;user-id=91673457;user-type= :linkoping!linkoping@linkoping.tmi.twitch.tv PRIVMSG #pajlada :Då kan du begära skadestånd och förtal Kappa) " ) ;
emoteTestMessages . emplace_back ( R " (@badge-info=subscriber/1;badges=subscriber/0;color=;display-name=jhoelsc;emotes=301683486:46-58,60-72,74-86/301683544:88-100;flags=0-4:S.6;id=1f1afcdd-d94c-4699-b35f-d214deb1e11a;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1588640587462;turbo=0;user-id=505763008;user-type= :jhoelsc!jhoelsc@jhoelsc.tmi.twitch.tv PRIVMSG #pajlada :pensé que no habría directo que bueno que si staryuukiLove staryuukiLove staryuukiLove staryuukiBits) " ) ;
emoteTestMessages . emplace_back ( R " (@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=41:6-13,16-23;flags=;id=97c28382-e8d2-45a0-bb5d-2305fc4ef139;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922036771;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm, Kreygasm) " ) ;
emoteTestMessages . emplace_back ( R " (@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=25:24-28/41:6-13,15-22;flags=;id=5a36536b-a952-43f7-9c41-88c829371b7a;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922039721;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm,Kreygasm Kappa (no space then space)) " ) ;
emoteTestMessages . emplace_back ( R " (@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=25:6-10/1902:12-16/88:18-25;flags=;id=aed9e67e-f8cd-493e-aa6b-da054edd7292;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922042881;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kappa.Keepo.PogChamp.extratext (3 emotes with extra text)) " ) ;
emoteTestMessages . emplace_back ( R " (@badge-info=;badges=moderator/1,partner/1;color=#5B99FF;display-name=StreamElements;emotes=86:30-39/822112:73-79;flags=22-27:S.5;id=03c3eec9-afd1-4858-a2e0-fccbf6ad8d1a;mod=1;room-id=11148817;subscriber=0;tmi-sent-ts=1588638345928;turbo=0;user-id=100135110;user-type=mod :streamelements!streamelements@streamelements.tmi.twitch.tv PRIVMSG #pajlada :╔ACTION A LOJA AINDA NÃO ESTÁ PRONTA BibleThump , AGUARDE... NOVIDADES EM BREVE FortOne╔) " ) ;
emoteTestMessages . emplace_back ( R " (@badge-info=subscriber/20;badges=moderator/1,subscriber/12;color=#19E6E6;display-name=randers;emotes=25:39-43;flags=;id=3ea97f01-abb2-4acf-bdb8-f52e79cd0324;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1588837097115;turbo=0;user-id=40286300;user-type=mod :randers!randers@randers.tmi.twitch.tv PRIVMSG #pajlada :Då kan du begära skadestånd och förtal Kappa) " ) ;
emoteTestMessages . emplace_back ( R " (@badge-info=subscriber/34;badges=moderator/1,subscriber/24;color=#FF0000;display-name=테스트계정420;emotes=41:6-13,15-22;flags=;id=a3196c7e-be4c-4b49-9c5a-8b8302b50c2a;mod=1;room-id=11148817;subscriber=1;tmi-sent-ts=1590922213730;turbo=0;user-id=117166826;user-type=mod :testaccount_420!testaccount_420@testaccount_420.tmi.twitch.tv PRIVMSG #pajlada :-tags Kreygasm,Kreygasm (no space)) " ) ;
2018-01-12 19:15:21 +01:00
// clang-format on
2018-10-23 07:20:02 +02:00
createWindowShortcut ( this , " F6 " , [ = ] {
2018-06-24 16:24:40 +02:00
const auto & messages = miscMessages ;
2018-06-05 14:08:55 +02:00
static int index = 0 ;
auto app = getApp ( ) ;
const auto & msg = messages [ index + + % messages . size ( ) ] ;
app - > twitch . server - > addFakeMessage ( msg ) ;
} ) ;
2018-06-07 17:43:21 +02:00
2019-09-08 12:45:25 +02:00
createWindowShortcut ( this , " F7 " , [ = ] {
const auto & messages = cheerMessages ;
static int index = 0 ;
const auto & msg = messages [ index + + % messages . size ( ) ] ;
getApp ( ) - > twitch . server - > addFakeMessage ( msg ) ;
} ) ;
2019-09-08 19:25:42 +02:00
2019-12-29 15:45:52 +01:00
createWindowShortcut ( this , " F8 " , [ = ] {
const auto & messages = linkMessages ;
static int index = 0 ;
auto app = getApp ( ) ;
const auto & msg = messages [ index + + % messages . size ( ) ] ;
app - > twitch . server - > addFakeMessage ( msg ) ;
} ) ;
2018-07-06 17:02:26 +02:00
createWindowShortcut ( this , " F9 " , [ = ] {
2020-08-08 15:37:22 +02:00
rapidjson : : Document doc ;
auto app = getApp ( ) ;
static bool alt = true ;
if ( alt )
{
doc . Parse ( channelRewardMessage ) ;
app - > twitch . server - > addFakeMessage ( channelRewardIRCMessage ) ;
app - > twitch . pubsub - > signals_ . pointReward . redeemed . invoke (
doc [ " data " ] [ " message " ] [ " data " ] [ " redemption " ] ) ;
alt = ! alt ;
}
else
{
doc . Parse ( channelRewardMessage2 ) ;
app - > twitch . pubsub - > signals_ . pointReward . redeemed . invoke (
doc [ " data " ] [ " message " ] [ " data " ] [ " redemption " ] ) ;
alt = ! alt ;
}
2018-06-07 17:43:21 +02:00
} ) ;
2019-09-08 19:25:42 +02:00
2020-09-26 14:21:46 +02:00
createWindowShortcut ( this , " F11 " , [ = ] {
const auto & messages = emoteTestMessages ;
static int index = 0 ;
const auto & msg = messages [ index + + % messages . size ( ) ] ;
getApp ( ) - > twitch . server - > addFakeMessage ( msg ) ;
} ) ;
2018-06-05 14:08:55 +02:00
# endif
2020-08-08 15:37:22 +02:00
} // namespace chatterino
2016-12-29 17:31:07 +01:00
2018-07-06 17:02:26 +02:00
void Window : : addShortcuts ( )
2018-07-05 11:42:40 +02:00
{
2018-07-06 17:02:26 +02:00
/// Initialize program-wide hotkeys
// Open settings
2020-10-31 16:42:48 +01:00
createWindowShortcut ( this , " CTRL+P " , [ this ] {
2020-11-08 12:02:19 +01:00
SettingsDialog : : showDialog ( this ) ;
2020-10-31 16:42:48 +01:00
} ) ;
2018-07-06 17:02:26 +02:00
// Switch tab
2018-08-06 21:17:03 +02:00
createWindowShortcut ( this , " CTRL+T " , [ this ] {
2018-08-11 22:23:06 +02:00
this - > notebook_ - > getOrAddSelectedPage ( ) - > appendNewSplit ( true ) ;
2018-08-06 21:17:03 +02:00
} ) ;
2019-08-04 16:57:34 +02:00
// CTRL + 1-8 to open corresponding tab.
for ( auto i = 0 ; i < 8 ; i + + )
{
2020-11-08 12:02:19 +01:00
const auto openTab = [ this , i ] {
this - > notebook_ - > selectIndex ( i ) ;
} ;
2020-12-12 14:58:59 +01:00
createWindowShortcut ( this , QString ( " CTRL+%1 " ) . arg ( i + 1 ) . toUtf8 ( ) ,
openTab ) ;
2019-08-04 16:57:34 +02:00
}
2020-11-08 12:02:19 +01:00
createWindowShortcut ( this , " CTRL+9 " , [ this ] {
this - > notebook_ - > selectLastTab ( ) ;
} ) ;
2018-07-06 17:02:26 +02:00
2020-11-08 12:02:19 +01:00
createWindowShortcut ( this , " CTRL+TAB " , [ this ] {
this - > notebook_ - > selectNextTab ( ) ;
} ) ;
createWindowShortcut ( this , " CTRL+SHIFT+TAB " , [ this ] {
this - > notebook_ - > selectPreviousTab ( ) ;
} ) ;
2019-08-04 15:51:17 +02:00
2020-08-13 18:02:23 +02:00
createWindowShortcut ( this , " CTRL+N " , [ this ] {
if ( auto page = dynamic_cast < SplitContainer * > (
this - > notebook_ - > getSelectedPage ( ) ) )
{
if ( auto split = page - > getSelectedSplit ( ) )
{
split - > popup ( ) ;
}
}
} ) ;
2018-07-06 17:02:26 +02:00
// Zoom in
{
auto s = new QShortcut ( QKeySequence : : ZoomIn , this ) ;
s - > setContext ( Qt : : WindowShortcut ) ;
QObject : : connect ( s , & QShortcut : : activated , this , [ ] {
2018-11-25 21:14:42 +01:00
getSettings ( ) - > setClampedUiScale (
getSettings ( ) - > getClampedUiScale ( ) + 0.1f ) ;
2018-07-06 17:02:26 +02:00
} ) ;
2017-01-16 03:15:07 +01:00
}
2018-07-06 17:02:26 +02:00
// Zoom out
{
auto s = new QShortcut ( QKeySequence : : ZoomOut , this ) ;
s - > setContext ( Qt : : WindowShortcut ) ;
QObject : : connect ( s , & QShortcut : : activated , this , [ ] {
2018-11-25 21:14:42 +01:00
getSettings ( ) - > setClampedUiScale (
getSettings ( ) - > getClampedUiScale ( ) - 0.1f ) ;
2018-07-06 17:02:26 +02:00
} ) ;
2017-01-16 03:15:07 +01:00
}
2017-01-28 22:35:23 +01:00
2018-07-06 17:02:26 +02:00
// New tab
2020-11-08 12:02:19 +01:00
createWindowShortcut ( this , " CTRL+SHIFT+T " , [ this ] {
this - > notebook_ - > addPage ( true ) ;
} ) ;
2017-06-07 10:09:24 +02:00
2018-07-06 17:02:26 +02:00
// Close tab
2020-11-08 12:02:19 +01:00
createWindowShortcut ( this , " CTRL+SHIFT+W " , [ this ] {
this - > notebook_ - > removeCurrentPage ( ) ;
} ) ;
2018-10-09 19:43:29 +02:00
// Reopen last closed split
createWindowShortcut ( this , " CTRL+G " , [ this ] {
2018-10-21 13:43:02 +02:00
if ( ClosedSplits : : empty ( ) )
{
2018-10-09 19:43:29 +02:00
return ;
}
ClosedSplits : : SplitInfo si = ClosedSplits : : pop ( ) ;
SplitContainer * splitContainer { nullptr } ;
2018-10-21 13:43:02 +02:00
if ( si . tab )
{
2018-10-09 19:43:29 +02:00
splitContainer = dynamic_cast < SplitContainer * > ( si . tab - > page ) ;
}
2018-10-21 13:43:02 +02:00
if ( ! splitContainer )
{
2018-10-09 19:43:29 +02:00
splitContainer = this - > notebook_ - > getOrAddSelectedPage ( ) ;
}
this - > notebook_ - > select ( splitContainer ) ;
Split * split = new Split ( splitContainer ) ;
split - > setChannel (
getApp ( ) - > twitch . server - > getOrAddChannel ( si . channelName ) ) ;
2018-10-13 14:34:33 +02:00
splitContainer - > appendSplit ( split ) ;
2018-10-09 19:43:29 +02:00
} ) ;
2020-02-02 14:31:37 +01:00
2020-08-13 20:05:54 +02:00
createWindowShortcut ( this , " CTRL+H " , [ ] {
2020-02-02 14:31:37 +01:00
getSettings ( ) - > hideSimilar . setValue ( ! getSettings ( ) - > hideSimilar ) ;
getApp ( ) - > windows - > forceLayoutChannelViews ( ) ;
} ) ;
2020-08-13 19:25:51 +02:00
createWindowShortcut ( this , " CTRL+K " , [ this ] {
auto quickSwitcher =
new QuickSwitcherPopup ( & getApp ( ) - > windows - > getMainWindow ( ) ) ;
quickSwitcher - > show ( ) ;
} ) ;
2017-12-18 21:02:17 +01:00
}
2019-06-09 16:13:06 +02:00
void Window : : addMenuBar ( )
{
QMenuBar * mainMenu = new QMenuBar ( ) ;
mainMenu - > setNativeMenuBar ( true ) ;
2019-08-04 15:29:54 +02:00
// First menu.
QMenu * menu = mainMenu - > addMenu ( QString ( ) ) ;
2019-06-09 16:13:06 +02:00
QAction * prefs = menu - > addAction ( QString ( ) ) ;
prefs - > setMenuRole ( QAction : : PreferencesRole ) ;
2020-10-31 16:42:48 +01:00
connect ( prefs , & QAction : : triggered , this , [ this ] {
2020-11-08 12:02:19 +01:00
SettingsDialog : : showDialog ( this ) ;
2020-10-31 16:42:48 +01:00
} ) ;
2019-08-04 15:29:54 +02:00
// Window menu.
QMenu * windowMenu = mainMenu - > addMenu ( QString ( " Window " ) ) ;
QAction * nextTab = windowMenu - > addAction ( QString ( " Select next tab " ) ) ;
nextTab - > setShortcuts ( { QKeySequence ( " Meta+Tab " ) } ) ;
2020-11-08 12:02:19 +01:00
connect ( nextTab , & QAction : : triggered , this , [ = ] {
this - > notebook_ - > selectNextTab ( ) ;
} ) ;
2019-08-04 15:29:54 +02:00
QAction * prevTab = windowMenu - > addAction ( QString ( " Select previous tab " ) ) ;
prevTab - > setShortcuts ( { QKeySequence ( " Meta+Shift+Tab " ) } ) ;
2020-11-08 12:02:19 +01:00
connect ( prevTab , & QAction : : triggered , this , [ = ] {
this - > notebook_ - > selectPreviousTab ( ) ;
} ) ;
2019-06-09 16:13:06 +02:00
}
2018-07-06 17:02:26 +02:00
void Window : : onAccountSelected ( )
2018-01-23 22:48:33 +01:00
{
2018-07-06 17:02:26 +02:00
auto user = getApp ( ) - > accounts - > twitch . getCurrent ( ) ;
2018-10-01 21:44:23 +02:00
2020-07-05 14:04:39 +02:00
// update title (also append username on Linux and MacOS)
QString windowTitle = Version : : instance ( ) . fullVersion ( ) ;
2018-06-21 22:02:35 +02:00
2020-07-05 14:04:39 +02:00
# if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
2018-10-21 13:43:02 +02:00
if ( user - > isAnon ( ) )
{
2020-07-05 14:04:39 +02:00
windowTitle + = " - not logged in " ;
2018-10-21 13:43:02 +02:00
}
else
{
2020-07-05 14:04:39 +02:00
windowTitle + = " - " + user - > getUserName ( ) ;
}
# endif
this - > setWindowTitle ( windowTitle ) ;
// update user
if ( this - > userLabel_ )
{
if ( user - > isAnon ( ) )
{
this - > userLabel_ - > getLabel ( ) . setText ( " anonymous " ) ;
}
else
2018-10-21 13:43:02 +02:00
{
2018-07-06 17:02:26 +02:00
this - > userLabel_ - > getLabel ( ) . setText ( user - > getUserName ( ) ) ;
}
2018-04-20 22:54:09 +02:00
}
2020-07-05 14:04:39 +02:00
}
2017-12-22 14:44:31 +01:00
2017-04-14 17:52:22 +02:00
} // namespace chatterino