Support displaying of video spoilers.

This commit is contained in:
John Preston 2022-12-13 10:29:48 +04:00
parent ae3659d15b
commit 3a38497c4c
2 changed files with 117 additions and 56 deletions

View file

@ -92,6 +92,10 @@ Gif::Gif(
setDocumentLinks(_data, realParent);
setStatusSize(Ui::FileStatusSizeReady);
if (_spoiler) {
createSpoilerLink(_spoiler.get());
}
refreshCaption();
if ((_dataMedia = _data->activeMediaView())) {
dataMediaCreated();
@ -328,9 +332,59 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
&& canBePlayed
&& CanPlayInline(_data);
const auto activeRoundPlaying = activeRoundStreamed();
auto paintx = 0, painty = 0, paintw = width(), painth = height();
auto captionw = paintw - st::msgPadding.left() - st::msgPadding.right();
const bool bubble = _parent->hasBubble();
const auto outbg = context.outbg;
const auto inWebPage = (_parent->media() != this);
const auto isRound = _data->isVideoMessage();
const auto rounding = inWebPage
? std::optional<Ui::BubbleRounding>()
: adjustedBubbleRoundingWithCaption(_caption);
if (bubble) {
if (!_caption.isEmpty()) {
painth -= st::mediaCaptionSkip + _caption.countHeight(captionw);
if (isBubbleBottom()) {
painth -= st::msgPadding.bottom();
}
}
}
auto usex = 0, usew = paintw;
const auto unwrapped = isUnwrapped();
const auto via = unwrapped ? item->Get<HistoryMessageVia>() : nullptr;
const auto reply = unwrapped ? _parent->displayedReply() : nullptr;
const auto forwarded = unwrapped ? item->Get<HistoryMessageForwarded>() : nullptr;
const auto rightAligned = unwrapped
&& outbg
&& !_parent->delegate()->elementIsChatWide();
if (via || reply || forwarded) {
usew = maxWidth() - additionalWidth(via, reply, forwarded);
if (rightAligned) {
usex = width() - usew;
}
}
if (isRound) {
accumulate_min(usew, painth);
}
if (rtl()) usex = width() - usex - usew;
QRect rthumb(style::rtlrect(usex + paintx, painty, usew, painth, width()));
const auto revealed = (!isRound && _spoiler)
? _spoiler->revealAnimation.value(_spoiler->revealed ? 1. : 0.)
: 1.;
const auto fullHiddenBySpoiler = (revealed == 0.);
if (revealed < 1.) {
validateSpoilerImageCache(rthumb.size(), rounding);
}
const auto startPlay = autoplay
&& !_streamed
&& !activeRoundPlaying;
&& !activeRoundPlaying
&& !fullHiddenBySpoiler;
if (startPlay) {
const_cast<Gif*>(this)->playAnimation(true);
} else {
@ -339,13 +393,6 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
const auto streamingMode = _streamed || activeRoundPlaying || autoplay;
const auto activeOwnPlaying = activeOwnStreamed();
auto paintx = 0, painty = 0, paintw = width(), painth = height();
auto captionw = paintw - st::msgPadding.left() - st::msgPadding.right();
const bool bubble = _parent->hasBubble();
const auto outbg = context.outbg;
const auto inWebPage = (_parent->media() != this);
const auto isRound = _data->isVideoMessage();
const auto unwrapped = isUnwrapped();
auto displayMute = false;
const auto streamed = activeRoundPlaying
? activeRoundPlaying
@ -372,38 +419,6 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
const auto radial = isRadialAnimation()
|| (streamedForWaiting && streamedForWaiting->waitingShown());
const auto rounding = inWebPage
? std::optional<Ui::BubbleRounding>()
: adjustedBubbleRoundingWithCaption(_caption);
if (bubble) {
if (!_caption.isEmpty()) {
painth -= st::mediaCaptionSkip + _caption.countHeight(captionw);
if (isBubbleBottom()) {
painth -= st::msgPadding.bottom();
}
}
}
auto usex = 0, usew = paintw;
const auto via = unwrapped ? item->Get<HistoryMessageVia>() : nullptr;
const auto reply = unwrapped ? _parent->displayedReply() : nullptr;
const auto forwarded = unwrapped ? item->Get<HistoryMessageForwarded>() : nullptr;
const auto rightAligned = unwrapped
&& outbg
&& !_parent->delegate()->elementIsChatWide();
if (via || reply || forwarded) {
usew = maxWidth() - additionalWidth(via, reply, forwarded);
if (rightAligned) {
usex = width() - usew;
}
}
if (isRound) {
accumulate_min(usew, painth);
}
if (rtl()) usex = width() - usex - usew;
QRect rthumb(style::rtlrect(usex + paintx, painty, usew, painth, width()));
if (!bubble && !unwrapped) {
Assert(rounding.has_value());
fillImageShadow(p, rthumb, *rounding, context);
@ -411,7 +426,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
const auto skipDrawingContent = context.skipDrawingParts
== PaintContext::SkipDrawingParts::Content;
if (streamed && !skipDrawingContent) {
if (streamed && !skipDrawingContent && !fullHiddenBySpoiler) {
auto paused = context.paused;
auto request = ::Media::Streaming::FrameRequest{
.outer = QSize(usew, painth) * cIntRetinaFactor(),
@ -474,18 +489,17 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
p.setOpacity(1.);
}
}
} else if (!skipDrawingContent) {
} else if (!skipDrawingContent && !fullHiddenBySpoiler) {
ensureDataMediaCreated();
validateThumbCache({ usew, painth }, isRound, rounding);
p.drawImage(rthumb, _thumbCache);
}
if (!isRound && _spoiler) {
fillImageSpoiler(
p,
_spoiler.get(),
rthumb,
context);
if (!isRound && revealed < 1.) {
p.setOpacity(1. - revealed);
p.drawImage(rthumb.topLeft(), _spoiler->background);
fillImageSpoiler(p, _spoiler.get(), rthumb, context);
p.setOpacity(1.);
}
if (context.selected()) {
if (isRound) {
@ -498,13 +512,14 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
if (radial
|| (!streamingMode
&& ((!loaded && !_data->loading()) || !autoplay))) {
const auto radialOpacity = (item->isSending() || _data->uploading())
const auto opacity = (item->isSending() || _data->uploading())
? 1.
: streamedForWaiting
? streamedForWaiting->waitingOpacity()
: (radial && loaded)
? _animation->radial.opacity()
: 1.;
const auto radialOpacity = opacity * revealed;
const auto innerSize = st::msgFileLayout.thumbSize;
auto inner = QRect(rthumb.x() + (rthumb.width() - innerSize) / 2, rthumb.y() + (rthumb.height() - innerSize) / 2, innerSize, innerSize);
p.setPen(Qt::NoPen);
@ -542,7 +557,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
if (icon) {
icon->paintInCenter(p, inner);
}
p.setOpacity(1);
p.setOpacity(revealed);
if (radial) {
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
if (streamedForWaiting && !_data->uploading()) {
@ -562,6 +577,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
sti->historyFileThumbRadialFg);
}
}
p.setOpacity(1.);
}
if (displayMute) {
auto muteRect = style::rtlrect(rthumb.x() + (rthumb.width() - st::historyVideoMessageMuteSize) / 2, rthumb.y() + st::msgDateImgDelta, st::historyVideoMessageMuteSize, st::historyVideoMessageMuteSize, width());
@ -808,6 +824,26 @@ QImage Gif::prepareThumbCache(QSize outer) const {
blurFromLarge ? large : blurred);
}
void Gif::validateSpoilerImageCache(
QSize outer,
std::optional<Ui::BubbleRounding> rounding) const {
Expects(_spoiler != nullptr);
const auto ratio = style::DevicePixelRatio();
if (_spoiler->background.size() == (outer * ratio)
&& _spoiler->backgroundRounding == rounding) {
return;
}
_spoiler->background = Images::Round(
PrepareWithBlurredBackground(
outer,
::Media::Streaming::ExpandDecision(),
nullptr,
_dataMedia->thumbnailInline()),
MediaRoundingMask(rounding));
_spoiler->backgroundRounding = rounding;
}
void Gif::drawCornerStatus(
Painter &p,
const PaintContext &context,
@ -984,7 +1020,9 @@ TextState Gif::textState(QPoint point, StateRequest request) const {
}
if (QRect(usex + paintx, painty, usew, painth).contains(point)) {
ensureDataMediaCreated();
result.link = _data->uploading()
result.link = (_spoiler && !_spoiler->revealed)
? _spoiler->link
: _data->uploading()
? _cancell
: _realParent->isSending()
? nullptr
@ -1105,6 +1143,15 @@ void Gif::drawGrouped(
const auto fullFeatured = fullFeaturedGrouped(sides);
const auto cornerDownload = fullFeatured && downloadInCorner();
const auto canBePlayed = _dataMedia->canBePlayed(_realParent);
const auto revealed = _spoiler
? _spoiler->revealAnimation.value(_spoiler->revealed ? 1. : 0.)
: 1.;
const auto fullHiddenBySpoiler = (revealed == 0.);
if (revealed < 1.) {
validateSpoilerImageCache(geometry.size(), rounding);
}
const auto autoplay = fullFeatured
&& autoplayEnabled()
&& canBePlayed
@ -1139,7 +1186,7 @@ void Gif::drawGrouped(
const auto radial = isRadialAnimation()
|| (streamedForWaiting && streamedForWaiting->waitingShown());
if (streamed) {
if (streamed && !fullHiddenBySpoiler) {
const auto original = sizeForAspectRatio();
const auto originalWidth = style::ConvertScale(original.width());
const auto originalHeight = style::ConvertScale(original.height());
@ -1171,11 +1218,18 @@ void Gif::drawGrouped(
streamed->markFrameShown();
}
}
} else {
} else if (!fullHiddenBySpoiler) {
validateGroupedCache(geometry, rounding, cacheKey, cache);
p.drawPixmap(geometry, *cache);
}
if (revealed < 1.) {
p.setOpacity(1. - revealed);
p.drawImage(geometry.topLeft(), _spoiler->background);
fillImageSpoiler(p, _spoiler.get(), geometry, context);
p.setOpacity(1.);
}
const auto overlayOpacity = context.selected()
? (1. - highlightOpacity)
: highlightOpacity;
@ -1191,13 +1245,14 @@ void Gif::drawGrouped(
if (radial
|| (!streamingMode
&& ((!loaded && !_data->loading()) || !autoplay))) {
const auto radialOpacity = (item->isSending() || _data->uploading())
const auto opacity = (item->isSending() || _data->uploading())
? 1.
: streamedForWaiting
? streamedForWaiting->waitingOpacity()
: (radial && loaded)
? _animation->radial.opacity()
: 1.;
const auto radialOpacity = opacity * revealed;
const auto radialSize = st::historyGroupRadialSize;
const auto inner = QRect(
geometry.x() + (geometry.width() - radialSize) / 2,
@ -1248,7 +1303,7 @@ void Gif::drawGrouped(
icon->paintInCenter(p, inner);
}
}
p.setOpacity(1);
p.setOpacity(revealed);
if (radial) {
const auto line = st::historyGroupRadialLine;
const auto rinner = inner.marginsRemoved({ line, line, line, line });
@ -1269,6 +1324,7 @@ void Gif::drawGrouped(
sti->historyFileThumbRadialFg);
}
}
p.setOpacity(1.);
}
if (fullFeatured) {
drawCornerStatus(p, context, geometry.topLeft());
@ -1289,7 +1345,9 @@ TextState Gif::getStateGrouped(
}
}
ensureDataMediaCreated();
return TextState(_parent, _data->uploading()
return TextState(_parent, (_spoiler && !_spoiler->revealed)
? _spoiler->link
: _data->uploading()
? _cancell
: _realParent->isSending()
? nullptr

View file

@ -183,6 +183,9 @@ private:
bool isEllipse,
std::optional<Ui::BubbleRounding> rounding) const;
[[nodiscard]] QImage prepareThumbCache(QSize outer) const;
void validateSpoilerImageCache(
QSize outer,
std::optional<Ui::BubbleRounding> rounding) const;
void validateGroupedCache(
const QRect &geometry,