mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
[poll-view] Added initial display of photo and stickers.
This commit is contained in:
@@ -20,6 +20,27 @@ namespace {
|
||||
constexpr auto kShortPollTimeout = 30 * crl::time(1000);
|
||||
constexpr auto kReloadAfterAutoCloseDelay = crl::time(1000);
|
||||
|
||||
void ProcessPollMedia(
|
||||
not_null<Data::Session*> owner,
|
||||
const MTPMessageMedia &media) {
|
||||
media.match([&](const MTPDmessageMediaPhoto &media) {
|
||||
if (const auto photo = media.vphoto()) {
|
||||
photo->match([&](const MTPDphoto &) {
|
||||
owner->processPhoto(*photo);
|
||||
}, [](const auto &) {
|
||||
});
|
||||
}
|
||||
}, [&](const MTPDmessageMediaDocument &media) {
|
||||
if (const auto document = media.vdocument()) {
|
||||
document->match([&](const MTPDdocument &) {
|
||||
owner->processDocument(*document);
|
||||
}, [](const auto &) {
|
||||
});
|
||||
}
|
||||
}, [](const auto &) {
|
||||
});
|
||||
}
|
||||
|
||||
const PollAnswer *AnswerByOption(
|
||||
const std::vector<PollAnswer> &list,
|
||||
const QByteArray &option) {
|
||||
@@ -95,6 +116,7 @@ bool PollData::applyChanges(const MTPDpoll &poll) {
|
||||
&session(),
|
||||
answer.vtext());
|
||||
if (const auto media = answer.vmedia()) {
|
||||
ProcessPollMedia(_owner, *media);
|
||||
result.media = PollMediaToInputMedia(*media);
|
||||
}
|
||||
return result;
|
||||
@@ -190,6 +212,7 @@ bool PollData::applyResults(const MTPPollResults &results) {
|
||||
}
|
||||
}
|
||||
if (const auto media = results.vsolution_media()) {
|
||||
ProcessPollMedia(_owner, *media);
|
||||
const auto parsed = PollMediaToInputMedia(*media);
|
||||
const auto changedMedia = !parsed
|
||||
? solutionMedia.has_value()
|
||||
|
||||
@@ -4359,7 +4359,24 @@ not_null<PollData*> Session::processPoll(const MTPPoll &data) {
|
||||
not_null<PollData*> Session::processPoll(const MTPDmessageMediaPoll &data) {
|
||||
const auto result = processPoll(data.vpoll());
|
||||
const auto media = data.vattached_media()
|
||||
? PollMediaToInputMedia(*data.vattached_media())
|
||||
? ([&] {
|
||||
const auto &attached = *data.vattached_media();
|
||||
attached.match([&](const MTPDmessageMediaPhoto &media) {
|
||||
const auto photo = media.vphoto();
|
||||
if (!photo || photo->type() != mtpc_photo) {
|
||||
return;
|
||||
}
|
||||
processPhoto(*photo);
|
||||
}, [&](const MTPDmessageMediaDocument &media) {
|
||||
const auto document = media.vdocument();
|
||||
if (!document || document->type() != mtpc_document) {
|
||||
return;
|
||||
}
|
||||
processDocument(*document);
|
||||
}, [](const auto &) {
|
||||
});
|
||||
return PollMediaToInputMedia(attached);
|
||||
})()
|
||||
: std::optional<MTPInputMedia>();
|
||||
const auto changedMedia = !media
|
||||
? result->attachedMedia.has_value()
|
||||
|
||||
@@ -25,10 +25,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/effects/fireworks_animation.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/dynamic_image.h"
|
||||
#include "ui/dynamic_thumbnails.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_poll.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "base/crc32hash.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "base/timer.h"
|
||||
@@ -52,6 +56,14 @@ constexpr auto kRollDuration = crl::time(400);
|
||||
constexpr auto kLargestRadialDuration = 30 * crl::time(1000);
|
||||
constexpr auto kCriticalCloseDuration = 5 * crl::time(1000);
|
||||
|
||||
[[nodiscard]] int PollAnswerMediaSize() {
|
||||
return st::historyPollRadio.diameter * 2;
|
||||
}
|
||||
|
||||
[[nodiscard]] int PollAnswerMediaSkip() {
|
||||
return st::historyPollPercentSkip * 2;
|
||||
}
|
||||
|
||||
struct PercentCounterItem {
|
||||
int index = 0;
|
||||
int percent = 0;
|
||||
@@ -171,6 +183,18 @@ struct Poll::Answer {
|
||||
not_null<PollData*> poll,
|
||||
const PollAnswer &original,
|
||||
Ui::Text::MarkedContext context);
|
||||
void fillMedia(
|
||||
not_null<PollData*> poll,
|
||||
const PollAnswer &original,
|
||||
FullMsgId fullId,
|
||||
Fn<void()> repaint);
|
||||
|
||||
enum class ThumbnailKind {
|
||||
None,
|
||||
Photo,
|
||||
Document,
|
||||
Emoji,
|
||||
};
|
||||
|
||||
Ui::Text::String text;
|
||||
QByteArray option;
|
||||
@@ -184,6 +208,10 @@ struct Poll::Answer {
|
||||
bool selected = false;
|
||||
ClickHandlerPtr handler;
|
||||
Ui::Animations::Simple selectedAnimation;
|
||||
std::shared_ptr<Ui::DynamicImage> thumbnail;
|
||||
bool thumbnailRounded = false;
|
||||
ThumbnailKind thumbnailKind = ThumbnailKind::None;
|
||||
uint64 thumbnailId = 0;
|
||||
mutable std::unique_ptr<Ui::RippleAnimation> ripple;
|
||||
};
|
||||
|
||||
@@ -231,6 +259,67 @@ void Poll::Answer::fillData(
|
||||
context);
|
||||
}
|
||||
|
||||
void Poll::Answer::fillMedia(
|
||||
not_null<PollData*> poll,
|
||||
const PollAnswer &original,
|
||||
FullMsgId fullId,
|
||||
Fn<void()> repaint) {
|
||||
auto updated = std::shared_ptr<Ui::DynamicImage>();
|
||||
auto rounded = false;
|
||||
auto kind = ThumbnailKind::None;
|
||||
auto id = uint64(0);
|
||||
if (const auto media = original.media) {
|
||||
media->match([&](const MTPDinputMediaPhoto &media) {
|
||||
const auto input = media.vid();
|
||||
if (input.type() != mtpc_inputPhoto) {
|
||||
return;
|
||||
}
|
||||
const auto &photo = input.c_inputPhoto();
|
||||
id = uint64(photo.vid().v);
|
||||
updated = Ui::MakePhotoThumbnailCenterCrop(
|
||||
poll->owner().photo(id),
|
||||
fullId);
|
||||
rounded = true;
|
||||
kind = ThumbnailKind::Photo;
|
||||
}, [&](const MTPDinputMediaDocument &media) {
|
||||
const auto input = media.vid();
|
||||
if (input.type() != mtpc_inputDocument) {
|
||||
return;
|
||||
}
|
||||
const auto &document = input.c_inputDocument();
|
||||
id = uint64(document.vid().v);
|
||||
const auto parsed = poll->owner().document(id);
|
||||
if (parsed->sticker()) {
|
||||
updated = Ui::MakeEmojiThumbnail(
|
||||
&poll->owner(),
|
||||
Data::SerializeCustomEmojiId(parsed));
|
||||
kind = ThumbnailKind::Emoji;
|
||||
} else {
|
||||
updated = Ui::MakeDocumentThumbnailCenterCrop(parsed, fullId);
|
||||
rounded = true;
|
||||
kind = ThumbnailKind::Document;
|
||||
}
|
||||
}, [](const auto &) {
|
||||
});
|
||||
}
|
||||
const auto same = (kind == thumbnailKind)
|
||||
&& (id == thumbnailId)
|
||||
&& (rounded == thumbnailRounded);
|
||||
if (same) {
|
||||
return;
|
||||
}
|
||||
if (thumbnail) {
|
||||
thumbnail->subscribeToUpdates(nullptr);
|
||||
}
|
||||
thumbnail = std::move(updated);
|
||||
thumbnailRounded = rounded;
|
||||
thumbnailKind = kind;
|
||||
thumbnailId = id;
|
||||
if (thumbnail) {
|
||||
thumbnail->subscribeToUpdates(std::move(repaint));
|
||||
}
|
||||
}
|
||||
|
||||
Poll::CloseInformation::CloseInformation(
|
||||
TimeId date,
|
||||
TimeId period,
|
||||
@@ -266,19 +355,24 @@ QSize Poll::countOptimalSize() {
|
||||
auto maxWidth = st::msgFileMinWidth;
|
||||
accumulate_max(maxWidth, paddings + _question.maxWidth());
|
||||
for (const auto &answer : _answers) {
|
||||
const auto media = answer.thumbnail
|
||||
? (PollAnswerMediaSize() + PollAnswerMediaSkip())
|
||||
: 0;
|
||||
accumulate_max(
|
||||
maxWidth,
|
||||
paddings
|
||||
+ st::historyPollAnswerPadding.left()
|
||||
+ answer.text.maxWidth()
|
||||
+ media
|
||||
+ st::historyPollAnswerPadding.right());
|
||||
}
|
||||
|
||||
const auto answersHeight = ranges::accumulate(ranges::views::all(
|
||||
_answers
|
||||
) | ranges::views::transform([](const Answer &answer) {
|
||||
const auto media = answer.thumbnail ? PollAnswerMediaSize() : 0;
|
||||
return st::historyPollAnswerPadding.top()
|
||||
+ answer.text.minHeight()
|
||||
+ std::max(answer.text.minHeight(), media)
|
||||
+ st::historyPollAnswerPadding.bottom();
|
||||
}), 0);
|
||||
|
||||
@@ -352,14 +446,25 @@ int Poll::countAnswerTop(
|
||||
return tshift;
|
||||
}
|
||||
|
||||
int Poll::countAnswerHeight(
|
||||
int Poll::countAnswerContentWidth(
|
||||
const Answer &answer,
|
||||
int innerWidth) const {
|
||||
const auto answerWidth = innerWidth
|
||||
- st::historyPollAnswerPadding.left()
|
||||
- st::historyPollAnswerPadding.right();
|
||||
const auto mediaWidth = answer.thumbnail
|
||||
? (PollAnswerMediaSize() + PollAnswerMediaSkip())
|
||||
: 0;
|
||||
return std::max(1, answerWidth - mediaWidth);
|
||||
}
|
||||
|
||||
int Poll::countAnswerHeight(
|
||||
const Answer &answer,
|
||||
int innerWidth) const {
|
||||
const auto media = answer.thumbnail ? PollAnswerMediaSize() : 0;
|
||||
const auto textWidth = countAnswerContentWidth(answer, innerWidth);
|
||||
return st::historyPollAnswerPadding.top()
|
||||
+ answer.text.countHeight(answerWidth)
|
||||
+ std::max(answer.text.countHeight(textWidth), media)
|
||||
+ st::historyPollAnswerPadding.bottom();
|
||||
}
|
||||
|
||||
@@ -545,6 +650,8 @@ void Poll::updateAnswers() {
|
||||
.repaint = [=] { repaint(); },
|
||||
.customEmojiLoopLimit = 2,
|
||||
});
|
||||
const auto repaintThumbnail = crl::guard(this, [=] { repaint(); });
|
||||
const auto fullId = _parent->data()->fullId();
|
||||
auto options = ranges::views::all(
|
||||
_poll->answers
|
||||
) | ranges::views::transform(&PollAnswer::option) | ranges::to_vector;
|
||||
@@ -571,6 +678,7 @@ void Poll::updateAnswers() {
|
||||
&PollAnswer::option);
|
||||
Assert(i != end(_poll->answers));
|
||||
answer.fillData(_poll, *i, context);
|
||||
answer.fillMedia(_poll, *i, fullId, repaintThumbnail);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -584,6 +692,7 @@ void Poll::updateAnswers() {
|
||||
&PollAnswer::option);
|
||||
Assert(i != end(_poll->answers));
|
||||
result.fillData(_poll, *i, context);
|
||||
result.fillMedia(_poll, *i, fullId, repaintThumbnail);
|
||||
return result;
|
||||
}) | ranges::to_vector;
|
||||
|
||||
@@ -1100,6 +1209,8 @@ int Poll::paintAnswer(
|
||||
const auto awidth = width
|
||||
- st::historyPollAnswerPadding.left()
|
||||
- st::historyPollAnswerPadding.right();
|
||||
const auto media = answer.thumbnail ? PollAnswerMediaSize() : 0;
|
||||
const auto textWidth = countAnswerContentWidth(answer, width);
|
||||
|
||||
if (answer.ripple) {
|
||||
p.setOpacity(st::historyPollRippleOpacity);
|
||||
@@ -1144,6 +1255,7 @@ int Poll::paintAnswer(
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
textWidth,
|
||||
height,
|
||||
context);
|
||||
p.setOpacity(1.);
|
||||
@@ -1167,13 +1279,49 @@ int Poll::paintAnswer(
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
textWidth,
|
||||
height,
|
||||
context);
|
||||
}
|
||||
|
||||
top += st::historyPollAnswerPadding.top();
|
||||
if (answer.thumbnail) {
|
||||
const auto target = QRect(
|
||||
aleft + awidth - media,
|
||||
top,
|
||||
media,
|
||||
media);
|
||||
if (!target.isEmpty()) {
|
||||
const auto image = answer.thumbnail->image(media);
|
||||
if (!image.isNull()) {
|
||||
const auto source = QRectF(QPointF(), QSizeF(image.size()));
|
||||
const auto kx = target.width() / source.width();
|
||||
const auto ky = target.height() / source.height();
|
||||
const auto scale = std::max(kx, ky);
|
||||
const auto size = QSizeF(
|
||||
source.width() * scale,
|
||||
source.height() * scale);
|
||||
const auto geometry = QRectF(
|
||||
target.x() + (target.width() - size.width()) / 2.,
|
||||
target.y() + (target.height() - size.height()) / 2.,
|
||||
size.width(),
|
||||
size.height());
|
||||
p.save();
|
||||
if (answer.thumbnailRounded) {
|
||||
auto path = QPainterPath();
|
||||
path.addRoundedRect(
|
||||
target,
|
||||
st::roundRadiusSmall,
|
||||
st::roundRadiusSmall);
|
||||
p.setClipPath(path);
|
||||
}
|
||||
p.drawImage(geometry, image, source);
|
||||
p.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
p.setPen(stm->historyTextFg);
|
||||
answer.text.drawLeft(p, aleft, top, awidth, outerWidth);
|
||||
answer.text.drawLeft(p, aleft, top, textWidth, outerWidth);
|
||||
|
||||
return height;
|
||||
}
|
||||
@@ -1268,20 +1416,18 @@ void Poll::paintFilling(
|
||||
int left,
|
||||
int top,
|
||||
int width,
|
||||
int contentWidth,
|
||||
int height,
|
||||
const PaintContext &context) const {
|
||||
const auto bottom = top + height;
|
||||
const auto st = context.st;
|
||||
const auto stm = context.messageStyle();
|
||||
const auto aleft = left + st::historyPollAnswerPadding.left();
|
||||
const auto awidth = width
|
||||
- st::historyPollAnswerPadding.left()
|
||||
- st::historyPollAnswerPadding.right();
|
||||
|
||||
top += st::historyPollAnswerPadding.top();
|
||||
|
||||
const auto thickness = st::historyPollFillingHeight;
|
||||
const auto max = awidth - st::historyPollFillingRight;
|
||||
const auto max = contentWidth - st::historyPollFillingRight;
|
||||
const auto size = anim::interpolate(st::historyPollFillingMin, max, filling);
|
||||
const auto radius = st::historyPollFillingRadius;
|
||||
const auto ftop = bottom - st::historyPollFillingBottom - thickness;
|
||||
|
||||
@@ -83,6 +83,9 @@ private:
|
||||
[[nodiscard]] int countAnswerTop(
|
||||
const Answer &answer,
|
||||
int innerWidth) const;
|
||||
[[nodiscard]] int countAnswerContentWidth(
|
||||
const Answer &answer,
|
||||
int innerWidth) const;
|
||||
[[nodiscard]] int countAnswerHeight(
|
||||
const Answer &answer,
|
||||
int innerWidth) const;
|
||||
@@ -149,6 +152,7 @@ private:
|
||||
int left,
|
||||
int top,
|
||||
int width,
|
||||
int contentWidth,
|
||||
int height,
|
||||
const PaintContext &context) const;
|
||||
void paintInlineFooter(
|
||||
|
||||
Reference in New Issue
Block a user