Add ability to pin Usercards to stay open even if it loses focus (#3884)

Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
Co-authored-by: James Upjohn <jammehcow@jammehcow.co.nz>
This commit is contained in:
Patrick Geneva 2022-11-12 07:21:43 -05:00 committed by GitHub
parent 070151fbc8
commit 06b28ea0ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 134 additions and 1 deletions

View file

@ -6,6 +6,7 @@
- Major: Added multi-channel searching to search dialog via keyboard shortcut. (Ctrl+Shift+F by default) (#3694, #3875)
- Major: Added support for emotes and badges from [7TV](https://7tv.app). [Wiki Page](https://wiki.chatterino.com/Third_party_services/#7tv) (#4002, #4062)
- Major: Added support for Right-to-Left Languages (#3958, #4139)
- Minor: Added ability to pin Usercards to stay open even if it loses focus. Only available if "Automatically close usercard when it loses focus" is enabled. (#3884)
- Minor: Allow hiding moderation actions in streamer mode. (#3926)
- Minor: Added highlights for `Elevated Messages`. (#4016)
- Minor: Removed total views from the usercard, as Twitch no longer updates the number. (#3792)

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="15.999924mm"
height="15.999949mm"
viewBox="0 0 15.999924 15.999949"
version="1.1"
id="svg5"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs2" /><g
id="layer2"
transform="translate(-4.439446e-5,3.0446178e-5)"><path
class="UnoptimicedTransforms"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 12.435417,-0.52916667 3.96875,3.96874997 V 3.96875 l -4.7625,4.7625 V 11.1125 L 11.1125,11.641667 H 10.847917 L 4.2333333,5.0270833 V 4.7625 L 4.7625,4.2333333 h 2.38125 l 4.7625,-4.76249997 z"
id="path234"
transform="matrix(1.0300653,0,0,1.0300668,-1.0336639,0.68131565)" /><path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.272538px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 5.098444,9.8113564 6.1885966,10.901511 1.2829102,15.807204 0.19275776,14.717051 Z"
id="path1157" /></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="15.999924mm"
height="15.999949mm"
viewBox="0 0 15.999924 15.999949"
version="1.1"
id="svg5"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs2" /><g
id="layer2"
transform="translate(-4.439446e-5,3.0446178e-5)"><path
class="UnoptimicedTransforms"
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 12.435417,-0.52916667 3.96875,3.96874997 V 3.96875 l -4.7625,4.7625 V 11.1125 L 11.1125,11.641667 H 10.847917 L 4.2333333,5.0270833 V 4.7625 L 4.7625,4.2333333 h 2.38125 l 4.7625,-4.76249997 z"
id="path234"
transform="matrix(1.0300653,0,0,1.0300668,-1.0336639,0.68131565)" /><path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.272538px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 5.098444,9.8113564 6.1885966,10.901511 1.2829102,15.807204 0.19275776,14.717051 Z"
id="path1157" /></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="15.999924mm"
height="15.999949mm"
viewBox="0 0 15.999924 15.999949"
version="1.1"
id="svg5"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs2" /><g
id="layer2"
transform="translate(-4.439446e-5,3.0446178e-5)"><path
class="UnoptimicedTransforms"
style="fill:#e25c41;fill-opacity:1;stroke:#e25c41;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 12.435417,-0.52916667 3.96875,3.96874997 V 3.96875 l -4.7625,4.7625 V 11.1125 L 11.1125,11.641667 H 10.847917 L 4.2333333,5.0270833 V 4.7625 L 4.7625,4.2333333 h 2.38125 l 4.7625,-4.76249997 z"
id="path234"
transform="matrix(1.0300653,0,0,1.0300668,-1.0336639,0.68131565)" /><path
style="fill:#e25c41;fill-opacity:1;stroke:#e25c41;stroke-width:0.272538px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 5.098444,9.8113564 6.1885966,10.901511 1.2829102,15.807204 0.19275776,14.717051 Z"
id="path1157" /></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -38,6 +38,12 @@
<file>buttons/modModeDisabled2.png</file>
<file>buttons/modModeEnabled.png</file>
<file>buttons/modModeEnabled2.png</file>
<file>buttons/pinDisabledDark.png</file>
<file>buttons/pinDisabledDark.svg</file>
<file>buttons/pinDisabledLight.png</file>
<file>buttons/pinDisabledLight.svg</file>
<file>buttons/pinEnabled.png</file>
<file>buttons/pinEnabled.svg</file>
<file>buttons/replyDark.png</file>
<file>buttons/replyDark.svg</file>
<file>buttons/replyThreadDark.png</file>

View file

@ -34,6 +34,9 @@ Resources2::Resources2()
this->buttons.modModeDisabled2 = QPixmap(":/buttons/modModeDisabled2.png");
this->buttons.modModeEnabled = QPixmap(":/buttons/modModeEnabled.png");
this->buttons.modModeEnabled2 = QPixmap(":/buttons/modModeEnabled2.png");
this->buttons.pinDisabledDark = QPixmap(":/buttons/pinDisabledDark.png");
this->buttons.pinDisabledLight = QPixmap(":/buttons/pinDisabledLight.png");
this->buttons.pinEnabled = QPixmap(":/buttons/pinEnabled.png");
this->buttons.replyDark = QPixmap(":/buttons/replyDark.png");
this->buttons.replyThreadDark = QPixmap(":/buttons/replyThreadDark.png");
this->buttons.search = QPixmap(":/buttons/search.png");

View file

@ -41,6 +41,9 @@ public:
QPixmap modModeDisabled2;
QPixmap modModeEnabled;
QPixmap modModeEnabled2;
QPixmap pinDisabledDark;
QPixmap pinDisabledLight;
QPixmap pinEnabled;
QPixmap replyDark;
QPixmap replyThreadDark;
QPixmap search;

View file

@ -278,10 +278,12 @@ void Theme::actuallyUpdate(double hue, double multiplier)
if (this->isLightTheme())
{
this->buttons.copy = getResources().buttons.copyDark;
this->buttons.pin = getResources().buttons.pinDisabledDark;
}
else
{
this->buttons.copy = getResources().buttons.copyLight;
this->buttons.pin = getResources().buttons.pinDisabledLight;
}
}

View file

@ -129,6 +129,7 @@ public:
struct {
QPixmap copy;
QPixmap pin;
} buttons;
void normalizeColor(QColor &color);

View file

@ -134,11 +134,13 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent,
Split *split)
: DraggablePopup(closeAutomatically, parent)
, split_(split)
, closeAutomatically_(closeAutomatically)
{
assert(split != nullptr &&
"split being nullptr causes lots of bugs down the road");
this->setWindowTitle("Usercard");
this->setStayInScreenRect(true);
this->updateFocusLoss();
HotkeyController::HotkeyMap actions{
{"delete",
@ -349,6 +351,22 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent,
this->ui_.localizedNameLabel->setVisible(false);
this->ui_.localizedNameCopyButton->setVisible(false);
// button to pin the window (only if we close automatically)
if (this->closeAutomatically_)
{
this->ui_.pinButton = box.emplace<Button>().getElement();
this->ui_.pinButton->setPixmap(
getApp()->themes->buttons.pin);
this->ui_.pinButton->setScaleIndependantSize(18, 18);
this->ui_.pinButton->setToolTip("Pin Window");
QObject::connect(this->ui_.pinButton, &Button::leftClicked,
[this]() {
this->closeAutomatically_ =
!this->closeAutomatically_;
this->updateFocusLoss();
});
}
}
// items on the left
@ -873,6 +891,26 @@ void UserInfoPopup::updateUserData()
this->ui_.ignoreHighlights->setEnabled(false);
}
void UserInfoPopup::updateFocusLoss()
{
if (this->closeAutomatically_)
{
this->setActionOnFocusLoss(BaseWindow::Delete);
if (this->ui_.pinButton != nullptr)
{
this->ui_.pinButton->setPixmap(getApp()->themes->buttons.pin);
}
}
else
{
this->setActionOnFocusLoss(BaseWindow::Nothing);
if (this->ui_.pinButton != nullptr)
{
this->ui_.pinButton->setPixmap(getResources().buttons.pinEnabled);
}
}
}
void UserInfoPopup::loadAvatar(const QUrl &url)
{
QNetworkRequest req(url);

View file

@ -36,6 +36,7 @@ private:
void installEvents();
void updateUserData();
void updateLatestMessages();
void updateFocusLoss();
void loadAvatar(const QUrl &url);
bool isMod_;
@ -46,8 +47,10 @@ private:
QString userName_;
QString userId_;
QString avatarUrl_;
// The channel the popup was opened from (e.g. /mentions or #forsen). Can be a special channel.
ChannelPtr channel_;
// The channel the messages are rendered from (e.g. #forsen). Can be a special channel, but will try to not be where possible.
ChannelPtr underlyingChannel_;
@ -55,6 +58,11 @@ private:
std::unique_ptr<pajlada::Signals::ScopedConnection> refreshConnection_;
// If we should close the dialog automatically if the user clicks out
// Initially set based on the "Automatically close usercard when it loses focus" setting
// If that setting is enabled, this can be toggled on and off using the pin in the top-right corner
bool closeAutomatically_;
struct {
Button *avatarButton = nullptr;
Button *localizedNameCopyButton = nullptr;
@ -64,6 +72,8 @@ private:
Label *followerCountLabel = nullptr;
Label *createdDateLabel = nullptr;
Label *userIDLabel = nullptr;
// Can be uninitialized if usercard is not configured to close on focus loss
Button *pinButton = nullptr;
Label *followageLabel = nullptr;
Label *subageLabel = nullptr;

View file

@ -700,7 +700,7 @@ void GeneralPage::initLayout(GeneralPageView &layout)
s.mentionUsersWithComma);
layout.addCheckbox("Show joined users (< 1000 chatters)", s.showJoins);
layout.addCheckbox("Show parted users (< 1000 chatters)", s.showParts);
layout.addCheckbox("Automatically close user popup when it loses focus",
layout.addCheckbox("Automatically close usercard when it loses focus",
s.autoCloseUserPopup);
layout.addCheckbox(
"Automatically close reply thread popup when it loses focus",