mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Add thumbnails to link tooltips if available (#1664)
This feature is off by default and can be enabled in the settings with the "Show link thumbnail" setting. This feature also requires the "Show link info when hovering" setting to be enabled. thumbnails support is only there for direct image links, twitch clips, and youtube links. can be expanded in the future in the /api repo Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
parent
1a4a468ab1
commit
8532c6d3bc
|
@ -1,6 +1,7 @@
|
|||
# Changelog
|
||||
|
||||
## Unversioned
|
||||
- Major: We now support image thumbnails coming from the link resolver. This feature is off by default and can be enabled in the settings with the "Show link thumbnail" setting. This feature also requires the "Show link info when hovering" setting to be enabled (#1664)
|
||||
- Major: Added image upload functionality to i.nuuls.com. This works by dragging and dropping an image into a split, or pasting an image into the text edit field. (#1332)
|
||||
- Minor: Emotes in the emote popup are now sorted in the same order as the tab completion (#1549)
|
||||
- Minor: Removed "Online Logs" functionality as services are shut down (#1640)
|
||||
|
|
|
@ -419,7 +419,8 @@ void MessageBuilder::addLink(const QString &origLink,
|
|||
LinkResolver::getLinkInfo(
|
||||
matchedLink, nullptr,
|
||||
[weakMessage = this->weakOf(), linkMELowercase, linkMEOriginal,
|
||||
matchedLink](QString tooltipText, Link originalLink) {
|
||||
matchedLink](QString tooltipText, Link originalLink,
|
||||
ImagePtr thumbnail) {
|
||||
auto shared = weakMessage.lock();
|
||||
if (!shared)
|
||||
{
|
||||
|
@ -436,6 +437,12 @@ void MessageBuilder::addLink(const QString &origLink,
|
|||
linkMELowercase->setLink(originalLink)->updateLink();
|
||||
linkMEOriginal->setLink(originalLink)->updateLink();
|
||||
}
|
||||
linkMELowercase->setThumbnail(thumbnail);
|
||||
linkMELowercase->setThumbnailType(
|
||||
MessageElement::ThumbnailType::Link_Thumbnail);
|
||||
linkMEOriginal->setThumbnail(thumbnail);
|
||||
linkMEOriginal->setThumbnailType(
|
||||
MessageElement::ThumbnailType::Link_Thumbnail);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,18 @@ MessageElement *MessageElement::setTooltip(const QString &tooltip)
|
|||
return this;
|
||||
}
|
||||
|
||||
MessageElement *MessageElement::setThumbnail(const ImagePtr &thumbnail)
|
||||
{
|
||||
this->thumbnail_ = thumbnail;
|
||||
return this;
|
||||
}
|
||||
|
||||
MessageElement *MessageElement::setThumbnailType(const ThumbnailType type)
|
||||
{
|
||||
this->thumbnailType_ = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
MessageElement *MessageElement::setTrailingSpace(bool value)
|
||||
{
|
||||
this->trailingSpace = value;
|
||||
|
@ -51,6 +63,16 @@ const QString &MessageElement::getTooltip() const
|
|||
return this->tooltip_;
|
||||
}
|
||||
|
||||
const ImagePtr &MessageElement::getThumbnail() const
|
||||
{
|
||||
return this->thumbnail_;
|
||||
}
|
||||
|
||||
const MessageElement::ThumbnailType &MessageElement::getThumbnailType() const
|
||||
{
|
||||
return this->thumbnailType_;
|
||||
}
|
||||
|
||||
const Link &MessageElement::getLink() const
|
||||
{
|
||||
return this->link_;
|
||||
|
|
|
@ -122,14 +122,23 @@ public:
|
|||
Update_Images = 4,
|
||||
Update_All = Update_Text | Update_Emotes | Update_Images
|
||||
};
|
||||
enum ThumbnailType : char {
|
||||
Link_Thumbnail = 1,
|
||||
};
|
||||
|
||||
virtual ~MessageElement();
|
||||
|
||||
MessageElement *setLink(const Link &link);
|
||||
MessageElement *setText(const QString &text);
|
||||
MessageElement *setTooltip(const QString &tooltip);
|
||||
MessageElement *setThumbnailType(const ThumbnailType type);
|
||||
MessageElement *setThumbnail(const ImagePtr &thumbnail);
|
||||
|
||||
MessageElement *setTrailingSpace(bool value);
|
||||
const QString &getTooltip() const;
|
||||
const ImagePtr &getThumbnail() const;
|
||||
const ThumbnailType &getThumbnailType() const;
|
||||
|
||||
const Link &getLink() const;
|
||||
bool hasTrailingSpace() const;
|
||||
MessageElementFlags getFlags() const;
|
||||
|
@ -148,6 +157,8 @@ private:
|
|||
QString text_;
|
||||
Link link_;
|
||||
QString tooltip_;
|
||||
ImagePtr thumbnail_;
|
||||
ThumbnailType thumbnailType_;
|
||||
MessageElementFlags flags_;
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "common/Common.hpp"
|
||||
#include "common/Env.hpp"
|
||||
#include "common/NetworkRequest.hpp"
|
||||
#include "messages/Image.hpp"
|
||||
#include "messages/Link.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
|
||||
|
@ -12,11 +13,11 @@ namespace chatterino {
|
|||
|
||||
void LinkResolver::getLinkInfo(
|
||||
const QString url, QObject *caller,
|
||||
std::function<void(QString, Link)> successCallback)
|
||||
std::function<void(QString, Link, ImagePtr)> successCallback)
|
||||
{
|
||||
if (!getSettings()->linkInfoTooltip)
|
||||
{
|
||||
successCallback("No link info loaded", Link(Link::Url, url));
|
||||
successCallback("No link info loaded", Link(Link::Url, url), nullptr);
|
||||
return;
|
||||
}
|
||||
// Uncomment to test crashes
|
||||
|
@ -25,14 +26,18 @@ void LinkResolver::getLinkInfo(
|
|||
QUrl::toPercentEncoding(url, "", "/:"))))
|
||||
.caller(caller)
|
||||
.timeout(30000)
|
||||
.onSuccess([successCallback, url](auto result) mutable -> Outcome {
|
||||
.onSuccess(
|
||||
[successCallback, url](NetworkResult result) mutable -> Outcome {
|
||||
auto root = result.parseJson();
|
||||
auto statusCode = root.value("status").toInt();
|
||||
QString response = QString();
|
||||
QString linkString = url;
|
||||
ImagePtr thumbnail = nullptr;
|
||||
if (statusCode == 200)
|
||||
{
|
||||
response = root.value("tooltip").toString();
|
||||
thumbnail =
|
||||
Image::fromUrl({root.value("thumbnail").toString()});
|
||||
if (getSettings()->unshortLinks)
|
||||
{
|
||||
linkString = root.value("link").toString();
|
||||
|
@ -43,12 +48,13 @@ void LinkResolver::getLinkInfo(
|
|||
response = root.value("message").toString();
|
||||
}
|
||||
successCallback(QUrl::fromPercentEncoding(response.toUtf8()),
|
||||
Link(Link::Url, linkString));
|
||||
Link(Link::Url, linkString), thumbnail);
|
||||
|
||||
return Success;
|
||||
})
|
||||
.onError([successCallback, url](auto /*result*/) {
|
||||
successCallback("No link info found", Link(Link::Url, url));
|
||||
successCallback("No link info found", Link(Link::Url, url),
|
||||
nullptr);
|
||||
})
|
||||
.execute();
|
||||
// });
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <QString>
|
||||
#include <functional>
|
||||
|
||||
#include "messages/Image.hpp"
|
||||
#include "messages/Link.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
@ -10,8 +11,9 @@ namespace chatterino {
|
|||
class LinkResolver
|
||||
{
|
||||
public:
|
||||
static void getLinkInfo(const QString url, QObject *caller,
|
||||
std::function<void(QString, Link)> callback);
|
||||
static void getLinkInfo(
|
||||
const QString url, QObject *caller,
|
||||
std::function<void(QString, Link, ImagePtr)> callback);
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
|
|
@ -161,6 +161,7 @@ public:
|
|||
/// Links
|
||||
BoolSetting linksDoubleClickOnly = {"/links/doubleClickToOpen", false};
|
||||
BoolSetting linkInfoTooltip = {"/links/linkInfoTooltip", false};
|
||||
IntSetting thumbnailSize = {"/appearance/thumbnailSize", 0};
|
||||
BoolSetting unshortLinks = {"/links/unshortLinks", false};
|
||||
BoolSetting lowercaseDomains = {"/links/linkLowercase", true};
|
||||
|
||||
|
|
|
@ -38,6 +38,14 @@ void TooltipPreviewImage::setImage(ImagePtr image)
|
|||
this->refreshTooltipWidgetPixmap();
|
||||
}
|
||||
|
||||
void TooltipPreviewImage::setImageScale(int w, int h)
|
||||
{
|
||||
this->imageWidth_ = w;
|
||||
this->imageHeight_ = h;
|
||||
|
||||
this->refreshTooltipWidgetPixmap();
|
||||
}
|
||||
|
||||
void TooltipPreviewImage::refreshTooltipWidgetPixmap()
|
||||
{
|
||||
auto tooltipWidget = TooltipWidget::instance();
|
||||
|
@ -45,8 +53,18 @@ void TooltipPreviewImage::refreshTooltipWidgetPixmap()
|
|||
if (this->image_ && !tooltipWidget->isHidden())
|
||||
{
|
||||
if (auto pixmap = this->image_->pixmapOrLoad())
|
||||
{
|
||||
if (this->imageWidth_ != 0 && this->imageHeight_)
|
||||
{
|
||||
tooltipWidget->setImage(pixmap->scaled(this->imageWidth_,
|
||||
this->imageHeight_,
|
||||
Qt::KeepAspectRatio));
|
||||
}
|
||||
else
|
||||
{
|
||||
tooltipWidget->setImage(*pixmap);
|
||||
}
|
||||
|
||||
this->attemptRefresh = false;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -9,6 +9,7 @@ class TooltipPreviewImage
|
|||
public:
|
||||
static TooltipPreviewImage &instance();
|
||||
void setImage(ImagePtr image);
|
||||
void setImageScale(int w, int h);
|
||||
|
||||
TooltipPreviewImage(const TooltipPreviewImage &) = delete;
|
||||
|
||||
|
@ -17,6 +18,9 @@ private:
|
|||
|
||||
private:
|
||||
ImagePtr image_ = nullptr;
|
||||
int imageWidth_ = 0;
|
||||
int imageHeight_ = 0;
|
||||
|
||||
std::vector<pajlada::Signals::ScopedConnection> connections_;
|
||||
|
||||
// attemptRefresh is set to true in case we want to preview an image that has not loaded yet (if pixmapOrLoad fails)
|
||||
|
|
|
@ -1259,6 +1259,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
|||
else
|
||||
{
|
||||
auto &tooltipPreviewImage = TooltipPreviewImage::instance();
|
||||
tooltipPreviewImage.setImageScale(0, 0);
|
||||
auto emoteElement = dynamic_cast<const EmoteElement *>(
|
||||
&hoverLayoutElement->getCreator());
|
||||
auto badgeElement = dynamic_cast<const BadgeElement *>(
|
||||
|
@ -1287,9 +1288,24 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto element = &hoverLayoutElement->getCreator();
|
||||
auto thumbnailSize = getSettings()->thumbnailSize;
|
||||
if (thumbnailSize == 0)
|
||||
{
|
||||
tooltipPreviewImage.setImage(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
tooltipPreviewImage.setImage(element->getThumbnail());
|
||||
if (element->getThumbnailType() ==
|
||||
MessageElement::ThumbnailType::Link_Thumbnail)
|
||||
{
|
||||
tooltipPreviewImage.setImageScale(thumbnailSize,
|
||||
thumbnailSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tooltipWidget->moveTo(this, event->globalPos());
|
||||
tooltipWidget->setWordWrap(isLinkValid);
|
||||
|
|
|
@ -521,6 +521,31 @@ void GeneralPage::initLayout(SettingsLayout &layout)
|
|||
},
|
||||
[](auto args) { return fuzzyToFloat(args.value, 63.f); });
|
||||
layout.addCheckbox("Show link info when hovering", s.linkInfoTooltip);
|
||||
layout.addDropdown<int>(
|
||||
"Show link thumbnail", {"Off", "Small", "Medium", "Large"},
|
||||
s.thumbnailSize,
|
||||
[](auto val) {
|
||||
if (val == 0)
|
||||
return QString("Off");
|
||||
else if (val == 100)
|
||||
return QString("Small");
|
||||
else if (val == 200)
|
||||
return QString("Medium");
|
||||
else if (val == 300)
|
||||
return QString("Large");
|
||||
else
|
||||
return QString::number(val);
|
||||
},
|
||||
[](auto args) {
|
||||
if (args.value == "Small")
|
||||
return 100;
|
||||
else if (args.value == "Medium")
|
||||
return 200;
|
||||
else if (args.value == "Large")
|
||||
return 300;
|
||||
|
||||
return fuzzyToInt(args.value, 0);
|
||||
});
|
||||
layout.addCheckbox("Double click to open links and other elements in chat",
|
||||
s.linksDoubleClickOnly);
|
||||
layout.addCheckbox("Unshorten links", s.unshortLinks);
|
||||
|
|
Loading…
Reference in a new issue