Estimate size of images to avoid layout shifts (#5192)

This commit is contained in:
nerix
2024-02-25 18:19:20 +01:00
committed by GitHub
parent 0cfd25ce8e
commit f285ada36c
13 changed files with 145 additions and 70 deletions
+15 -6
View File
@@ -27,22 +27,31 @@ ChannelPointReward::ChannelPointReward(const QJsonObject &redemption)
}
auto imageValue = reward.value("image");
// From Twitch docs
// The size is only an estimation, the actual size might vary.
constexpr QSize baseSize(28, 28);
if (imageValue.isObject())
{
auto imageObject = imageValue.toObject();
this->image = ImageSet{
Image::fromUrl({imageObject.value("url_1x").toString()}, 1),
Image::fromUrl({imageObject.value("url_2x").toString()}, 0.5),
Image::fromUrl({imageObject.value("url_4x").toString()}, 0.25),
Image::fromUrl({imageObject.value("url_1x").toString()}, 1,
baseSize),
Image::fromUrl({imageObject.value("url_2x").toString()}, 0.5,
baseSize * 2),
Image::fromUrl({imageObject.value("url_4x").toString()}, 0.25,
baseSize * 4),
};
}
else
{
static const ImageSet defaultImage{
Image::fromUrl({TWITCH_CHANNEL_POINT_REWARD_URL("1.png")}, 1),
Image::fromUrl({TWITCH_CHANNEL_POINT_REWARD_URL("2.png")}, 0.5),
Image::fromUrl({TWITCH_CHANNEL_POINT_REWARD_URL("4.png")}, 0.25)};
Image::fromUrl({TWITCH_CHANNEL_POINT_REWARD_URL("1.png")}, 1,
baseSize),
Image::fromUrl({TWITCH_CHANNEL_POINT_REWARD_URL("2.png")}, 0.5,
baseSize * 2),
Image::fromUrl({TWITCH_CHANNEL_POINT_REWARD_URL("4.png")}, 0.25,
baseSize * 4)};
this->image = defaultImage;
}
}
+19 -7
View File
@@ -18,6 +18,13 @@
#include <QThread>
#include <QUrlQuery>
namespace {
// From Twitch docs - expected size for a badge (1x)
constexpr QSize BADGE_BASE_SIZE(18, 18);
} // namespace
namespace chatterino {
void TwitchBadges::loadTwitchBadges()
@@ -37,9 +44,12 @@ void TwitchBadges::loadTwitchBadges()
.name = EmoteName{},
.images =
ImageSet{
Image::fromUrl(version.imageURL1x, 1),
Image::fromUrl(version.imageURL2x, .5),
Image::fromUrl(version.imageURL4x, .25),
Image::fromUrl(version.imageURL1x, 1,
BADGE_BASE_SIZE),
Image::fromUrl(version.imageURL2x, .5,
BADGE_BASE_SIZE * 2),
Image::fromUrl(version.imageURL4x, .25,
BADGE_BASE_SIZE * 4),
},
.tooltip = Tooltip{version.title},
.homePage = version.clickURL,
@@ -100,17 +110,19 @@ void TwitchBadges::parseTwitchBadges(QJsonObject root)
for (auto vIt = versions.begin(); vIt != versions.end(); ++vIt)
{
auto versionObj = vIt.value().toObject();
auto emote = Emote{
.name = {""},
.images =
ImageSet{
Image::fromUrl(
{versionObj.value("image_url_1x").toString()}, 1),
{versionObj.value("image_url_1x").toString()}, 1,
BADGE_BASE_SIZE),
Image::fromUrl(
{versionObj.value("image_url_2x").toString()}, .5),
{versionObj.value("image_url_2x").toString()}, .5,
BADGE_BASE_SIZE * 2),
Image::fromUrl(
{versionObj.value("image_url_4x").toString()}, .25),
{versionObj.value("image_url_4x").toString()}, .25,
BADGE_BASE_SIZE * 4),
},
.tooltip = Tooltip{versionObj.value("title").toString()},
.homePage = Url{versionObj.value("click_url").toString()},
+21 -15
View File
@@ -72,6 +72,9 @@ namespace {
// Maximum number of chatters to fetch when refreshing chatters
constexpr auto MAX_CHATTERS_TO_FETCH = 5000;
// From Twitch docs - expected size for a badge (1x)
constexpr QSize BASE_BADGE_SIZE(18, 18);
} // namespace
TwitchChannel::TwitchChannel(const QString &name)
@@ -1466,9 +1469,12 @@ void TwitchChannel::refreshBadges()
.name = EmoteName{},
.images =
ImageSet{
Image::fromUrl(version.imageURL1x, 1),
Image::fromUrl(version.imageURL2x, .5),
Image::fromUrl(version.imageURL4x, .25),
Image::fromUrl(version.imageURL1x, 1,
BASE_BADGE_SIZE),
Image::fromUrl(version.imageURL2x, .5,
BASE_BADGE_SIZE * 2),
Image::fromUrl(version.imageURL4x, .25,
BASE_BADGE_SIZE * 4),
},
.tooltip = Tooltip{version.title},
.homePage = version.clickURL,
@@ -1543,25 +1549,25 @@ void TwitchChannel::refreshCheerEmotes()
// Combine the prefix (e.g. BibleThump) with the tier (1, 100 etc.)
auto emoteTooltip =
set.prefix + tier.id + "<br>Twitch Cheer Emote";
auto makeImageSet = [](const HelixCheermoteImage &image) {
return ImageSet{
Image::fromUrl(image.imageURL1x, 1.0,
BASE_BADGE_SIZE),
Image::fromUrl(image.imageURL2x, 0.5,
BASE_BADGE_SIZE * 2),
Image::fromUrl(image.imageURL4x, 0.25,
BASE_BADGE_SIZE * 4),
};
};
cheerEmote.animatedEmote = std::make_shared<Emote>(Emote{
.name = EmoteName{"cheer emote"},
.images =
ImageSet{
tier.darkAnimated.imageURL1x,
tier.darkAnimated.imageURL2x,
tier.darkAnimated.imageURL4x,
},
.images = makeImageSet(tier.darkAnimated),
.tooltip = Tooltip{emoteTooltip},
.homePage = Url{},
});
cheerEmote.staticEmote = std::make_shared<Emote>(Emote{
.name = EmoteName{"cheer emote"},
.images =
ImageSet{
tier.darkStatic.imageURL1x,
tier.darkStatic.imageURL2x,
tier.darkStatic.imageURL4x,
},
.images = makeImageSet(tier.darkStatic),
.tooltip = Tooltip{emoteTooltip},
.homePage = Url{},
});
+5 -3
View File
@@ -44,12 +44,14 @@ EmotePtr TwitchEmotes::getOrCreateEmote(const EmoteId &id,
if (!shared)
{
// From Twitch docs - expected size for an emote (1x)
constexpr QSize baseSize(28, 28);
(*cache)[id] = shared = std::make_shared<Emote>(Emote{
EmoteName{name},
ImageSet{
Image::fromUrl(getEmoteLink(id, "1.0"), 1),
Image::fromUrl(getEmoteLink(id, "2.0"), 0.5),
Image::fromUrl(getEmoteLink(id, "3.0"), 0.25),
Image::fromUrl(getEmoteLink(id, "1.0"), 1, baseSize),
Image::fromUrl(getEmoteLink(id, "2.0"), 0.5, baseSize * 2),
Image::fromUrl(getEmoteLink(id, "3.0"), 0.25, baseSize * 4),
},
Tooltip{name.toHtmlEscaped() + "<br>Twitch Emote"},
});