mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Support spoilers in reply previews / pinned bar.
This commit is contained in:
parent
46bae9ed74
commit
d02819db13
17 changed files with 280 additions and 101 deletions
|
@ -1198,26 +1198,29 @@ bool DocumentData::isStickerSetInstalled() const {
|
||||||
|
|
||||||
Image *DocumentData::getReplyPreview(
|
Image *DocumentData::getReplyPreview(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
not_null<PeerData*> context) {
|
not_null<PeerData*> context,
|
||||||
|
bool spoiler) {
|
||||||
if (!hasThumbnail()) {
|
if (!hasThumbnail()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (!_replyPreview) {
|
} else if (!_replyPreview) {
|
||||||
_replyPreview = std::make_unique<Data::ReplyPreview>(this);
|
_replyPreview = std::make_unique<Data::ReplyPreview>(this);
|
||||||
}
|
}
|
||||||
return _replyPreview->image(origin, context);
|
return _replyPreview->image(origin, context, spoiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
Image *DocumentData::getReplyPreview(not_null<HistoryItem*> item) {
|
Image *DocumentData::getReplyPreview(not_null<HistoryItem*> item) {
|
||||||
return getReplyPreview(item->fullId(), item->history()->peer);
|
const auto media = item->media();
|
||||||
|
const auto spoiler = media && media->hasSpoiler();
|
||||||
|
return getReplyPreview(item->fullId(), item->history()->peer, spoiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DocumentData::replyPreviewLoaded() const {
|
bool DocumentData::replyPreviewLoaded(bool spoiler) const {
|
||||||
if (!hasThumbnail()) {
|
if (!hasThumbnail()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (!_replyPreview) {
|
} else if (!_replyPreview) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _replyPreview->loaded();
|
return _replyPreview->loaded(spoiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
StickerData *DocumentData::sticker() const {
|
StickerData *DocumentData::sticker() const {
|
||||||
|
|
|
@ -142,9 +142,10 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] Image *getReplyPreview(
|
[[nodiscard]] Image *getReplyPreview(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
not_null<PeerData*> context);
|
not_null<PeerData*> context,
|
||||||
|
bool spoiler);
|
||||||
[[nodiscard]] Image *getReplyPreview(not_null<HistoryItem*> item);
|
[[nodiscard]] Image *getReplyPreview(not_null<HistoryItem*> item);
|
||||||
[[nodiscard]] bool replyPreviewLoaded() const;
|
[[nodiscard]] bool replyPreviewLoaded(bool spoiler) const;
|
||||||
|
|
||||||
[[nodiscard]] StickerData *sticker() const;
|
[[nodiscard]] StickerData *sticker() const;
|
||||||
[[nodiscard]] Data::FileOrigin stickerSetOrigin() const;
|
[[nodiscard]] Data::FileOrigin stickerSetOrigin() const;
|
||||||
|
|
|
@ -618,7 +618,7 @@ Image *MediaPhoto::replyPreview() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaPhoto::replyPreviewLoaded() const {
|
bool MediaPhoto::replyPreviewLoaded() const {
|
||||||
return _photo->replyPreviewLoaded();
|
return _photo->replyPreviewLoaded(_spoiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextWithEntities MediaPhoto::notificationText() const {
|
TextWithEntities MediaPhoto::notificationText() const {
|
||||||
|
@ -854,7 +854,7 @@ Image *MediaFile::replyPreview() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaFile::replyPreviewLoaded() const {
|
bool MediaFile::replyPreviewLoaded() const {
|
||||||
return _document->replyPreviewLoaded();
|
return _document->replyPreviewLoaded(_spoiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemPreview MediaFile::toPreview(ToPreviewOptions options) const {
|
ItemPreview MediaFile::toPreview(ToPreviewOptions options) const {
|
||||||
|
@ -1479,10 +1479,11 @@ Image *MediaWebPage::replyPreview() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaWebPage::replyPreviewLoaded() const {
|
bool MediaWebPage::replyPreviewLoaded() const {
|
||||||
|
const auto spoiler = false;
|
||||||
if (const auto document = MediaWebPage::document()) {
|
if (const auto document = MediaWebPage::document()) {
|
||||||
return document->replyPreviewLoaded();
|
return document->replyPreviewLoaded(spoiler);
|
||||||
} else if (const auto photo = MediaWebPage::photo()) {
|
} else if (const auto photo = MediaWebPage::photo()) {
|
||||||
return photo->replyPreviewLoaded();
|
return photo->replyPreviewLoaded(spoiler);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1552,10 +1553,11 @@ Image *MediaGame::replyPreview() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaGame::replyPreviewLoaded() const {
|
bool MediaGame::replyPreviewLoaded() const {
|
||||||
|
const auto spoiler = false;
|
||||||
if (const auto document = _game->document) {
|
if (const auto document = _game->document) {
|
||||||
return document->replyPreviewLoaded();
|
return document->replyPreviewLoaded(spoiler);
|
||||||
} else if (const auto photo = _game->photo) {
|
} else if (const auto photo = _game->photo) {
|
||||||
return photo->replyPreviewLoaded();
|
return photo->replyPreviewLoaded(spoiler);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1675,8 +1677,9 @@ Image *MediaInvoice::replyPreview() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaInvoice::replyPreviewLoaded() const {
|
bool MediaInvoice::replyPreviewLoaded() const {
|
||||||
|
const auto spoiler = false;
|
||||||
if (const auto photo = _invoice.photo) {
|
if (const auto photo = _invoice.photo) {
|
||||||
return photo->replyPreviewLoaded();
|
return photo->replyPreviewLoaded(spoiler);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,22 +209,25 @@ bool PhotoData::uploading() const {
|
||||||
|
|
||||||
Image *PhotoData::getReplyPreview(
|
Image *PhotoData::getReplyPreview(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
not_null<PeerData*> context) {
|
not_null<PeerData*> context,
|
||||||
|
bool spoiler) {
|
||||||
if (!_replyPreview) {
|
if (!_replyPreview) {
|
||||||
_replyPreview = std::make_unique<Data::ReplyPreview>(this);
|
_replyPreview = std::make_unique<Data::ReplyPreview>(this);
|
||||||
}
|
}
|
||||||
return _replyPreview->image(origin, context);
|
return _replyPreview->image(origin, context, spoiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
Image *PhotoData::getReplyPreview(not_null<HistoryItem*> item) {
|
Image *PhotoData::getReplyPreview(not_null<HistoryItem*> item) {
|
||||||
return getReplyPreview(item->fullId(), item->history()->peer);
|
const auto media = item->media();
|
||||||
|
const auto spoiler = media && media->hasSpoiler();
|
||||||
|
return getReplyPreview(item->fullId(), item->history()->peer, spoiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhotoData::replyPreviewLoaded() const {
|
bool PhotoData::replyPreviewLoaded(bool spoiler) const {
|
||||||
if (!_replyPreview) {
|
if (!_replyPreview) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _replyPreview->loaded();
|
return _replyPreview->loaded(spoiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoData::setRemoteLocation(
|
void PhotoData::setRemoteLocation(
|
||||||
|
|
|
@ -66,9 +66,10 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] Image *getReplyPreview(
|
[[nodiscard]] Image *getReplyPreview(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
not_null<PeerData*> context);
|
not_null<PeerData*> context,
|
||||||
|
bool spoiler);
|
||||||
[[nodiscard]] Image *getReplyPreview(not_null<HistoryItem*> item);
|
[[nodiscard]] Image *getReplyPreview(not_null<HistoryItem*> item);
|
||||||
[[nodiscard]] bool replyPreviewLoaded() const;
|
[[nodiscard]] bool replyPreviewLoaded(bool spoiler) const;
|
||||||
|
|
||||||
void setRemoteLocation(
|
void setRemoteLocation(
|
||||||
int32 dc,
|
int32 dc,
|
||||||
|
|
|
@ -27,7 +27,11 @@ ReplyPreview::ReplyPreview(not_null<PhotoData*> photo)
|
||||||
|
|
||||||
ReplyPreview::~ReplyPreview() = default;
|
ReplyPreview::~ReplyPreview() = default;
|
||||||
|
|
||||||
void ReplyPreview::prepare(not_null<Image*> image, Images::Options options) {
|
void ReplyPreview::prepare(
|
||||||
|
not_null<Image*> image,
|
||||||
|
Images::Options options,
|
||||||
|
bool spoiler) {
|
||||||
|
using namespace Images;
|
||||||
if (image->isNull()) {
|
if (image->isNull()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -41,24 +45,34 @@ void ReplyPreview::prepare(not_null<Image*> image, Images::Options options) {
|
||||||
: QSize(
|
: QSize(
|
||||||
st::msgReplyBarSize.height(),
|
st::msgReplyBarSize.height(),
|
||||||
h * st::msgReplyBarSize.height() / w);
|
h * st::msgReplyBarSize.height() / w);
|
||||||
thumbSize *= cIntRetinaFactor();
|
thumbSize *= style::DevicePixelRatio();
|
||||||
options |= Images::Option::TransparentBackground;
|
options |= Option::TransparentBackground;
|
||||||
auto outerSize = st::msgReplyBarSize.height();
|
auto outerSize = st::msgReplyBarSize.height();
|
||||||
auto bitmap = image->pixNoCache(
|
auto original = spoiler
|
||||||
thumbSize,
|
? image->original().scaled(
|
||||||
{ .options = options, .outer = { outerSize, outerSize } });
|
{ 40, 40 },
|
||||||
_image = std::make_unique<Image>(bitmap.toImage());
|
Qt::KeepAspectRatio,
|
||||||
_good = ((options & Images::Option::Blur) == 0);
|
Qt::SmoothTransformation)
|
||||||
|
: image->original();
|
||||||
|
auto prepared = Prepare(std::move(original), thumbSize, {
|
||||||
|
.options = options | (spoiler ? Option::Blur : Option()),
|
||||||
|
.outer = { outerSize, outerSize },
|
||||||
|
});
|
||||||
|
(spoiler ? _spoilered : _regular) = std::make_unique<Image>(
|
||||||
|
std::move(prepared));
|
||||||
|
_good = spoiler || ((options & Option::Blur) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Image *ReplyPreview::image(
|
Image *ReplyPreview::image(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
not_null<PeerData*> context) {
|
not_null<PeerData*> context,
|
||||||
if (_checked) {
|
bool spoiler) {
|
||||||
return _image.get();
|
auto &image = spoiler ? _spoilered : _regular;
|
||||||
}
|
auto &checked = spoiler ? _checkedSpoilered : _checkedRegular;
|
||||||
if (_document) {
|
if (checked) {
|
||||||
if (!_image || (!_good && _document->hasThumbnail())) {
|
return image.get();
|
||||||
|
} else if (_document) {
|
||||||
|
if (!image || (!_good && _document->hasThumbnail())) {
|
||||||
if (!_documentMedia) {
|
if (!_documentMedia) {
|
||||||
_documentMedia = _document->createMediaView();
|
_documentMedia = _document->createMediaView();
|
||||||
_documentMedia->thumbnailWanted(origin);
|
_documentMedia->thumbnailWanted(origin);
|
||||||
|
@ -67,51 +81,67 @@ Image *ReplyPreview::image(
|
||||||
const auto option = _document->isVideoMessage()
|
const auto option = _document->isVideoMessage()
|
||||||
? Images::Option::RoundCircle
|
? Images::Option::RoundCircle
|
||||||
: Images::Option::None;
|
: Images::Option::None;
|
||||||
if (thumbnail) {
|
if (spoiler) {
|
||||||
|
if (const auto image = _documentMedia->thumbnailInline()) {
|
||||||
|
prepare(image, option, true);
|
||||||
|
} else if (thumbnail) {
|
||||||
|
prepare(thumbnail, option, true);
|
||||||
|
}
|
||||||
|
} else if (thumbnail) {
|
||||||
prepare(thumbnail, option);
|
prepare(thumbnail, option);
|
||||||
} else if (!_image) {
|
} else if (!image) {
|
||||||
if (const auto image = _documentMedia->thumbnailInline()) {
|
if (const auto image = _documentMedia->thumbnailInline()) {
|
||||||
prepare(image, option | Images::Option::Blur);
|
prepare(image, option | Images::Option::Blur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_good || !_document->hasThumbnail()) {
|
if (_good || !_document->hasThumbnail()) {
|
||||||
_checked = true;
|
checked = true;
|
||||||
_documentMedia = nullptr;
|
_documentMedia = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Assert(_photo != nullptr);
|
Assert(_photo != nullptr);
|
||||||
if (!_image || !_good) {
|
if (!image || !_good) {
|
||||||
const auto inlineThumbnailBytes = _photo->inlineThumbnailBytes();
|
const auto inlineThumbnailBytes = _photo->inlineThumbnailBytes();
|
||||||
if (!_photoMedia) {
|
if (!_photoMedia) {
|
||||||
_photoMedia = _photo->createMediaView();
|
_photoMedia = _photo->createMediaView();
|
||||||
}
|
}
|
||||||
|
using Size = PhotoSize;
|
||||||
const auto loadThumbnail = inlineThumbnailBytes.isEmpty()
|
const auto loadThumbnail = inlineThumbnailBytes.isEmpty()
|
||||||
|| _photoMedia->autoLoadThumbnailAllowed(context);
|
|| (!spoiler
|
||||||
|
&& _photoMedia->autoLoadThumbnailAllowed(context));
|
||||||
if (loadThumbnail) {
|
if (loadThumbnail) {
|
||||||
_photoMedia->wanted(PhotoSize::Small, origin);
|
_photoMedia->wanted(Size::Small, origin);
|
||||||
}
|
}
|
||||||
if (const auto small = _photoMedia->image(PhotoSize::Small)) {
|
if (spoiler) {
|
||||||
prepare(small, Images::Option(0));
|
const auto option = Images::Option::Blur;
|
||||||
} else if (const auto large = _photoMedia->image(
|
if (const auto blurred = _photoMedia->thumbnailInline()) {
|
||||||
PhotoSize::Large)) {
|
prepare(blurred, {}, true);
|
||||||
prepare(large, Images::Option(0));
|
} else if (const auto small = _photoMedia->image(Size::Small)) {
|
||||||
} else if (!_image) {
|
prepare(small, {}, true);
|
||||||
|
} else if (const auto large = _photoMedia->image(Size::Large)) {
|
||||||
|
prepare(large, {}, true);
|
||||||
|
}
|
||||||
|
} else if (const auto small = _photoMedia->image(Size::Small)) {
|
||||||
|
prepare(small, {});
|
||||||
|
} else if (const auto large = _photoMedia->image(Size::Large)) {
|
||||||
|
prepare(large, {});
|
||||||
|
} else if (!image) {
|
||||||
if (const auto blurred = _photoMedia->thumbnailInline()) {
|
if (const auto blurred = _photoMedia->thumbnailInline()) {
|
||||||
prepare(blurred, Images::Option::Blur);
|
prepare(blurred, Images::Option::Blur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_good) {
|
if (_good) {
|
||||||
_checked = true;
|
checked = true;
|
||||||
_photoMedia = nullptr;
|
_photoMedia = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _image.get();
|
return image.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReplyPreview::loaded() const {
|
bool ReplyPreview::loaded(bool spoiler) const {
|
||||||
return _checked;
|
return spoiler ? _checkedSpoilered : _checkedRegular;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -25,19 +25,25 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] Image *image(
|
[[nodiscard]] Image *image(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
not_null<PeerData*> context);
|
not_null<PeerData*> context,
|
||||||
[[nodiscard]] bool loaded() const;
|
bool spoiler);
|
||||||
|
[[nodiscard]] bool loaded(bool spoiler) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void prepare(not_null<Image*> image, Images::Options options);
|
void prepare(
|
||||||
|
not_null<Image*> image,
|
||||||
|
Images::Options options,
|
||||||
|
bool spoiler = false);
|
||||||
|
|
||||||
std::unique_ptr<Image> _image;
|
std::unique_ptr<Image> _regular;
|
||||||
|
std::unique_ptr<Image> _spoilered;
|
||||||
PhotoData *_photo = nullptr;
|
PhotoData *_photo = nullptr;
|
||||||
DocumentData *_document = nullptr;
|
DocumentData *_document = nullptr;
|
||||||
std::shared_ptr<PhotoMedia> _photoMedia;
|
std::shared_ptr<PhotoMedia> _photoMedia;
|
||||||
std::shared_ptr<DocumentMedia> _documentMedia;
|
std::shared_ptr<DocumentMedia> _documentMedia;
|
||||||
bool _good = false;
|
bool _good = false;
|
||||||
bool _checked = false;
|
bool _checkedRegular = false;
|
||||||
|
bool _checkedSpoilered = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -283,9 +283,10 @@ bool HistoryMessageReply::updateData(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replyToMsg) {
|
if (replyToMsg) {
|
||||||
|
const auto repaint = [=] { holder->customEmojiRepaint(); };
|
||||||
const auto context = Core::MarkedTextContext{
|
const auto context = Core::MarkedTextContext{
|
||||||
.session = &holder->history()->session(),
|
.session = &holder->history()->session(),
|
||||||
.customEmojiRepaint = [=] { holder->customEmojiRepaint(); },
|
.customEmojiRepaint = repaint,
|
||||||
};
|
};
|
||||||
replyToText.setMarkedText(
|
replyToText.setMarkedText(
|
||||||
st::messageTextStyle,
|
st::messageTextStyle,
|
||||||
|
@ -312,9 +313,17 @@ bool HistoryMessageReply::updateData(
|
||||||
? replyToMsg->from()->id
|
? replyToMsg->from()->id
|
||||||
: PeerId(0);
|
: PeerId(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto media = replyToMsg->media();
|
||||||
|
if (!media || !media->hasReplyPreview() || !media->hasSpoiler()) {
|
||||||
|
spoiler = nullptr;
|
||||||
|
} else if (!spoiler) {
|
||||||
|
spoiler = std::make_unique<Ui::SpoilerAnimation>(repaint);
|
||||||
|
}
|
||||||
} else if (force) {
|
} else if (force) {
|
||||||
replyToMsgId = 0;
|
replyToMsgId = 0;
|
||||||
replyToColorKey = PeerId(0);
|
replyToColorKey = PeerId(0);
|
||||||
|
spoiler = nullptr;
|
||||||
}
|
}
|
||||||
if (force) {
|
if (force) {
|
||||||
holder->history()->owner().requestItemResize(holder);
|
holder->history()->owner().requestItemResize(holder);
|
||||||
|
@ -463,14 +472,15 @@ void HistoryMessageReply::paint(
|
||||||
|
|
||||||
if (w > st::msgReplyBarSkip) {
|
if (w > st::msgReplyBarSkip) {
|
||||||
if (replyToMsg) {
|
if (replyToMsg) {
|
||||||
auto hasPreview = replyToMsg->media() ? replyToMsg->media()->hasReplyPreview() : false;
|
const auto media = replyToMsg->media();
|
||||||
|
auto hasPreview = media && media->hasReplyPreview();
|
||||||
if (hasPreview && w < st::msgReplyBarSkip + st::msgReplyBarSize.height()) {
|
if (hasPreview && w < st::msgReplyBarSkip + st::msgReplyBarSize.height()) {
|
||||||
hasPreview = false;
|
hasPreview = false;
|
||||||
}
|
}
|
||||||
auto previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0;
|
auto previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0;
|
||||||
|
|
||||||
if (hasPreview) {
|
if (hasPreview) {
|
||||||
if (const auto image = replyToMsg->media()->replyPreview()) {
|
if (const auto image = media->replyPreview()) {
|
||||||
auto to = style::rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x);
|
auto to = style::rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x);
|
||||||
const auto preview = image->pixSingle(
|
const auto preview = image->pixSingle(
|
||||||
image->size() / style::DevicePixelRatio(),
|
image->size() / style::DevicePixelRatio(),
|
||||||
|
@ -482,6 +492,16 @@ void HistoryMessageReply::paint(
|
||||||
.outer = to.size(),
|
.outer = to.size(),
|
||||||
});
|
});
|
||||||
p.drawPixmap(to.x(), to.y(), preview);
|
p.drawPixmap(to.x(), to.y(), preview);
|
||||||
|
if (spoiler) {
|
||||||
|
holder->clearCustomEmojiRepaint();
|
||||||
|
Ui::FillSpoilerRect(
|
||||||
|
p,
|
||||||
|
to,
|
||||||
|
Ui::DefaultImageSpoiler().frame(
|
||||||
|
spoiler->index(
|
||||||
|
context.now,
|
||||||
|
context.paused)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (w > st::msgReplyBarSkip + previewSkip) {
|
if (w > st::msgReplyBarSkip + previewSkip) {
|
||||||
|
|
|
@ -246,6 +246,7 @@ struct HistoryMessageReply
|
||||||
WebPageId replyToWebPageId = 0;
|
WebPageId replyToWebPageId = 0;
|
||||||
ReplyToMessagePointer replyToMsg;
|
ReplyToMessagePointer replyToMsg;
|
||||||
std::unique_ptr<HistoryMessageVia> replyToVia;
|
std::unique_ptr<HistoryMessageVia> replyToVia;
|
||||||
|
std::unique_ptr<Ui::SpoilerAnimation> spoiler;
|
||||||
ClickHandlerPtr replyToLnk;
|
ClickHandlerPtr replyToLnk;
|
||||||
mutable Ui::Text::String replyToName, replyToText;
|
mutable Ui::Text::String replyToName, replyToText;
|
||||||
mutable int replyToVersion = 0;
|
mutable int replyToVersion = 0;
|
||||||
|
|
|
@ -7490,20 +7490,44 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
p.setInactive(
|
p.setInactive(
|
||||||
controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any));
|
controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any));
|
||||||
p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg);
|
p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg);
|
||||||
|
|
||||||
|
const auto media = (!drawWebPagePreview && drawMsgText)
|
||||||
|
? drawMsgText->media()
|
||||||
|
: nullptr;
|
||||||
|
const auto hasPreview = media && media->hasReplyPreview();
|
||||||
|
const auto preview = hasPreview ? media->replyPreview() : nullptr;
|
||||||
|
const auto spoilered = preview && media->hasSpoiler();
|
||||||
|
if (!spoilered) {
|
||||||
|
_replySpoiler = nullptr;
|
||||||
|
} else if (!_replySpoiler) {
|
||||||
|
_replySpoiler = std::make_unique<Ui::SpoilerAnimation>([=] {
|
||||||
|
updateField();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
|
if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
|
||||||
|
const auto now = crl::now();
|
||||||
|
const auto paused = p.inactive();
|
||||||
auto replyLeft = st::historyReplySkip;
|
auto replyLeft = st::historyReplySkip;
|
||||||
(_editMsgId ? st::historyEditIcon : st::historyReplyIcon).paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
|
(_editMsgId ? st::historyEditIcon : st::historyReplyIcon).paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
|
||||||
if (!drawWebPagePreview) {
|
if (!drawWebPagePreview) {
|
||||||
if (drawMsgText) {
|
if (drawMsgText) {
|
||||||
if (drawMsgText->media() && drawMsgText->media()->hasReplyPreview()) {
|
if (hasPreview) {
|
||||||
if (const auto image = drawMsgText->media()->replyPreview()) {
|
if (preview) {
|
||||||
auto to = QRect(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height());
|
auto to = QRect(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height());
|
||||||
p.drawPixmap(to.x(), to.y(), image->pixSingle(
|
p.drawPixmap(to.x(), to.y(), preview->pixSingle(
|
||||||
image->size() / style::DevicePixelRatio(),
|
preview->size() / style::DevicePixelRatio(),
|
||||||
{
|
{
|
||||||
.options = Images::Option::RoundSmall,
|
.options = Images::Option::RoundSmall,
|
||||||
.outer = to.size(),
|
.outer = to.size(),
|
||||||
}));
|
}));
|
||||||
|
if (_replySpoiler) {
|
||||||
|
Ui::FillSpoilerRect(
|
||||||
|
p,
|
||||||
|
to,
|
||||||
|
Ui::DefaultImageSpoiler().frame(
|
||||||
|
_replySpoiler->index(now, paused)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
|
replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
|
||||||
}
|
}
|
||||||
|
@ -7521,8 +7545,8 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
||||||
.availableWidth = width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right(),
|
.availableWidth = width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right(),
|
||||||
.palette = &st::historyComposeAreaPalette,
|
.palette = &st::historyComposeAreaPalette,
|
||||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||||
.now = crl::now(),
|
.now = now,
|
||||||
.paused = p.inactive(),
|
.paused = paused,
|
||||||
.elisionLines = 1,
|
.elisionLines = 1,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -70,6 +70,7 @@ class RequestsBar;
|
||||||
struct PreparedList;
|
struct PreparedList;
|
||||||
class SendFilesWay;
|
class SendFilesWay;
|
||||||
class SendAsButton;
|
class SendAsButton;
|
||||||
|
class SpoilerAnimation;
|
||||||
enum class ReportReason;
|
enum class ReportReason;
|
||||||
class ChooseThemeController;
|
class ChooseThemeController;
|
||||||
class ContinuousScroll;
|
class ContinuousScroll;
|
||||||
|
@ -626,6 +627,7 @@ private:
|
||||||
|
|
||||||
HistoryItem *_replyEditMsg = nullptr;
|
HistoryItem *_replyEditMsg = nullptr;
|
||||||
Ui::Text::String _replyEditMsgText;
|
Ui::Text::String _replyEditMsgText;
|
||||||
|
std::unique_ptr<Ui::SpoilerAnimation> _replySpoiler;
|
||||||
mutable base::Timer _updateEditTimeLeftDisplay;
|
mutable base::Timer _updateEditTimeLeftDisplay;
|
||||||
|
|
||||||
object_ptr<Ui::IconButton> _fieldBarCancel;
|
object_ptr<Ui::IconButton> _fieldBarCancel;
|
||||||
|
|
|
@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_forum_topic.h"
|
#include "data/data_forum_topic.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "ui/chat/forward_options_box.h"
|
#include "ui/chat/forward_options_box.h"
|
||||||
|
#include "ui/effects/spoiler_mess.h"
|
||||||
#include "ui/text/text_options.h"
|
#include "ui/text/text_options.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
@ -306,33 +307,35 @@ void ForwardPanel::paint(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const_cast<ForwardPanel*>(this)->checkTexts();
|
const_cast<ForwardPanel*>(this)->checkTexts();
|
||||||
|
const auto now = crl::now();
|
||||||
|
const auto paused = p.inactive();
|
||||||
const auto firstItem = _data.items.front();
|
const auto firstItem = _data.items.front();
|
||||||
const auto firstMedia = firstItem->media();
|
const auto firstMedia = firstItem->media();
|
||||||
const auto hasPreview = (_data.items.size() < 2)
|
const auto hasPreview = (_data.items.size() < 2)
|
||||||
&& firstMedia
|
&& firstMedia
|
||||||
&& firstMedia->hasReplyPreview();
|
&& firstMedia->hasReplyPreview();
|
||||||
const auto preview = hasPreview ? firstMedia->replyPreview() : nullptr;
|
const auto preview = hasPreview ? firstMedia->replyPreview() : nullptr;
|
||||||
|
const auto spoiler = preview && firstMedia->hasSpoiler();
|
||||||
|
if (!spoiler) {
|
||||||
|
_spoiler = nullptr;
|
||||||
|
} else if (!_spoiler) {
|
||||||
|
_spoiler = std::make_unique<Ui::SpoilerAnimation>(_repaint);
|
||||||
|
}
|
||||||
if (preview) {
|
if (preview) {
|
||||||
auto to = QRect(
|
auto to = QRect(
|
||||||
x,
|
x,
|
||||||
y + st::msgReplyPadding.top(),
|
y + st::msgReplyPadding.top(),
|
||||||
st::msgReplyBarSize.height(),
|
st::msgReplyBarSize.height(),
|
||||||
st::msgReplyBarSize.height());
|
st::msgReplyBarSize.height());
|
||||||
if (preview->width() == preview->height()) {
|
p.drawPixmap(to.x(), to.y(), preview->pixSingle(
|
||||||
p.drawPixmap(to.x(), to.y(), preview->pix());
|
preview->size() / style::DevicePixelRatio(),
|
||||||
} else {
|
{
|
||||||
auto from = (preview->width() > preview->height())
|
.options = Images::Option::RoundSmall,
|
||||||
? QRect(
|
.outer = to.size(),
|
||||||
(preview->width() - preview->height()) / 2,
|
}));
|
||||||
0,
|
if (_spoiler) {
|
||||||
preview->height(),
|
Ui::FillSpoilerRect(p, to, Ui::DefaultImageSpoiler().frame(
|
||||||
preview->height())
|
_spoiler->index(now, paused)));
|
||||||
: QRect(
|
|
||||||
0,
|
|
||||||
(preview->height() - preview->width()) / 2,
|
|
||||||
preview->width(),
|
|
||||||
preview->width());
|
|
||||||
p.drawPixmap(to, preview->pix(), from);
|
|
||||||
}
|
}
|
||||||
const auto skip = st::msgReplyBarSize.height()
|
const auto skip = st::msgReplyBarSize.height()
|
||||||
+ st::msgReplyBarSkip
|
+ st::msgReplyBarSkip
|
||||||
|
@ -355,8 +358,8 @@ void ForwardPanel::paint(
|
||||||
.availableWidth = available,
|
.availableWidth = available,
|
||||||
.palette = &st::historyComposeAreaPalette,
|
.palette = &st::historyComposeAreaPalette,
|
||||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||||
.now = crl::now(),
|
.now = now,
|
||||||
.paused = p.inactive(),
|
.paused = paused,
|
||||||
.elisionLines = 1,
|
.elisionLines = 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
class Painter;
|
class Painter;
|
||||||
class HistoryItem;
|
class HistoryItem;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class SpoilerAnimation;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Thread;
|
class Thread;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
@ -57,6 +61,7 @@ private:
|
||||||
|
|
||||||
rpl::event_stream<> _itemsUpdated;
|
rpl::event_stream<> _itemsUpdated;
|
||||||
Ui::Text::String _from, _text;
|
Ui::Text::String _from, _text;
|
||||||
|
mutable std::unique_ptr<Ui::SpoilerAnimation> _spoiler;
|
||||||
int _nameVersion = 0;
|
int _nameVersion = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,8 +38,9 @@ namespace {
|
||||||
[[nodiscard]] Ui::MessageBarContent ContentWithPreview(
|
[[nodiscard]] Ui::MessageBarContent ContentWithPreview(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
Image *preview,
|
Image *preview,
|
||||||
|
bool spoiler,
|
||||||
Fn<void()> repaint) {
|
Fn<void()> repaint) {
|
||||||
auto result = ContentWithoutPreview(item, std::move(repaint));
|
auto result = ContentWithoutPreview(item, repaint);
|
||||||
if (!preview) {
|
if (!preview) {
|
||||||
static const auto kEmpty = [&] {
|
static const auto kEmpty = [&] {
|
||||||
const auto size = st::historyReplyHeight * cIntRetinaFactor();
|
const auto size = st::historyReplyHeight * cIntRetinaFactor();
|
||||||
|
@ -51,8 +52,10 @@ namespace {
|
||||||
return result;
|
return result;
|
||||||
}();
|
}();
|
||||||
result.preview = kEmpty;
|
result.preview = kEmpty;
|
||||||
|
result.spoilerRepaint = nullptr;
|
||||||
} else {
|
} else {
|
||||||
result.preview = preview->original();
|
result.preview = preview->original();
|
||||||
|
result.spoilerRepaint = spoiler ? repaint : nullptr;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +93,11 @@ namespace {
|
||||||
}) | rpl::then(
|
}) | rpl::then(
|
||||||
rpl::single(kFullLoaded)
|
rpl::single(kFullLoaded)
|
||||||
) | rpl::map([=] {
|
) | rpl::map([=] {
|
||||||
return ContentWithPreview(item, media->replyPreview(), repaint);
|
return ContentWithPreview(
|
||||||
|
item,
|
||||||
|
media->replyPreview(),
|
||||||
|
media->hasSpoiler(),
|
||||||
|
repaint);
|
||||||
});
|
});
|
||||||
}) | rpl::flatten_latest();
|
}) | rpl::flatten_latest();
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,8 +71,8 @@ bool DrawWebPageDataPreview(
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto preview = photo
|
const auto preview = photo
|
||||||
? photo->getReplyPreview(Data::FileOrigin(), context)
|
? photo->getReplyPreview(Data::FileOrigin(), context, false)
|
||||||
: document->getReplyPreview(Data::FileOrigin(), context);
|
: document->getReplyPreview(Data::FileOrigin(), context, false);
|
||||||
if (preview) {
|
if (preview) {
|
||||||
const auto w = preview->width();
|
const auto w = preview->width();
|
||||||
const auto h = preview->height();
|
const auto h = preview->height();
|
||||||
|
|
|
@ -140,6 +140,7 @@ void MessageBar::tweenTo(MessageBarContent &&content) {
|
||||||
? RectPart::Bottom
|
? RectPart::Bottom
|
||||||
: RectPart::None;
|
: RectPart::None;
|
||||||
animation.imageFrom = grabImagePart();
|
animation.imageFrom = grabImagePart();
|
||||||
|
animation.spoilerFrom = std::move(_spoiler);
|
||||||
animation.bodyOrTextFrom = grabBodyOrTextPart(animation.bodyAnimation);
|
animation.bodyOrTextFrom = grabBodyOrTextPart(animation.bodyAnimation);
|
||||||
const auto sameLength = SameFirstPartLength(
|
const auto sameLength = SameFirstPartLength(
|
||||||
_content.title,
|
_content.title,
|
||||||
|
@ -208,6 +209,12 @@ void MessageBar::updateFromContent(MessageBarContent &&content) {
|
||||||
Ui::DialogTextOptions(),
|
Ui::DialogTextOptions(),
|
||||||
_content.context);
|
_content.context);
|
||||||
_image = prepareImage(_content.preview);
|
_image = prepareImage(_content.preview);
|
||||||
|
if (!_content.spoilerRepaint) {
|
||||||
|
_spoiler = nullptr;
|
||||||
|
} else if (!_spoiler) {
|
||||||
|
_spoiler = std::make_unique<SpoilerAnimation>(
|
||||||
|
_content.spoilerRepaint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect MessageBar::imageRect() const {
|
QRect MessageBar::imageRect() const {
|
||||||
|
@ -258,10 +265,21 @@ auto MessageBar::makeGrabGuard() {
|
||||||
auto imageShown = _animation
|
auto imageShown = _animation
|
||||||
? std::move(_animation->imageShown)
|
? std::move(_animation->imageShown)
|
||||||
: Ui::Animations::Simple();
|
: Ui::Animations::Simple();
|
||||||
return gsl::finally([&, shown = std::move(imageShown)]() mutable {
|
auto spoiler = std::move(_spoiler);
|
||||||
|
auto fromSpoiler = _animation
|
||||||
|
? std::move(_animation->spoilerFrom)
|
||||||
|
: nullptr;
|
||||||
|
return gsl::finally([
|
||||||
|
&,
|
||||||
|
shown = std::move(imageShown),
|
||||||
|
spoiler = std::move(spoiler),
|
||||||
|
fromSpoiler = std::move(fromSpoiler)
|
||||||
|
]() mutable {
|
||||||
if (_animation) {
|
if (_animation) {
|
||||||
_animation->imageShown = std::move(shown);
|
_animation->imageShown = std::move(shown);
|
||||||
|
_animation->spoilerFrom = std::move(fromSpoiler);
|
||||||
}
|
}
|
||||||
|
_spoiler = std::move(spoiler);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,12 +376,20 @@ void MessageBar::paint(Painter &p) {
|
||||||
: (_animation->movingTo == RectPart::Top)
|
: (_animation->movingTo == RectPart::Top)
|
||||||
? (shiftTo - shiftFull)
|
? (shiftTo - shiftFull)
|
||||||
: (shiftTo + shiftFull);
|
: (shiftTo + shiftFull);
|
||||||
|
const auto now = crl::now();
|
||||||
|
const auto paused = p.inactive();
|
||||||
|
|
||||||
paintLeftBar(p);
|
paintLeftBar(p);
|
||||||
|
|
||||||
if (!_animation) {
|
if (!_animation) {
|
||||||
if (!_image.isNull()) {
|
if (!_image.isNull()) {
|
||||||
p.drawPixmap(image, _image);
|
paintImageWithSpoiler(
|
||||||
|
p,
|
||||||
|
image,
|
||||||
|
_image,
|
||||||
|
_spoiler.get(),
|
||||||
|
now,
|
||||||
|
paused);
|
||||||
}
|
}
|
||||||
} else if (!_animation->imageTo.isNull()
|
} else if (!_animation->imageTo.isNull()
|
||||||
|| (!_animation->imageFrom.isNull()
|
|| (!_animation->imageFrom.isNull()
|
||||||
|
@ -381,14 +407,30 @@ void MessageBar::paint(Painter &p) {
|
||||||
}();
|
}();
|
||||||
if (_animation->bodyMoved.animating()) {
|
if (_animation->bodyMoved.animating()) {
|
||||||
p.setOpacity(1. - progress);
|
p.setOpacity(1. - progress);
|
||||||
p.drawPixmap(
|
paintImageWithSpoiler(
|
||||||
|
p,
|
||||||
rect.translated(0, shiftFrom),
|
rect.translated(0, shiftFrom),
|
||||||
_animation->imageFrom);
|
_animation->imageFrom,
|
||||||
|
_animation->spoilerFrom.get(),
|
||||||
|
now,
|
||||||
|
paused);
|
||||||
p.setOpacity(progress);
|
p.setOpacity(progress);
|
||||||
p.drawPixmap(rect.translated(0, shiftTo), _animation->imageTo);
|
paintImageWithSpoiler(
|
||||||
|
p,
|
||||||
|
rect.translated(0, shiftTo),
|
||||||
|
_animation->imageTo,
|
||||||
|
_spoiler.get(),
|
||||||
|
now,
|
||||||
|
paused);
|
||||||
p.setOpacity(1.);
|
p.setOpacity(1.);
|
||||||
} else {
|
} else {
|
||||||
p.drawPixmap(rect, _image);
|
paintImageWithSpoiler(
|
||||||
|
p,
|
||||||
|
rect,
|
||||||
|
_image,
|
||||||
|
_spoiler.get(),
|
||||||
|
now,
|
||||||
|
paused);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!_animation || _animation->bodyAnimation == BodyAnimation::None) {
|
if (!_animation || _animation->bodyAnimation == BodyAnimation::None) {
|
||||||
|
@ -409,8 +451,8 @@ void MessageBar::paint(Painter &p) {
|
||||||
.availableWidth = body.width(),
|
.availableWidth = body.width(),
|
||||||
.palette = &_st.textPalette,
|
.palette = &_st.textPalette,
|
||||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||||
.now = crl::now(),
|
.now = now,
|
||||||
.paused = p.inactive(),
|
.paused = paused,
|
||||||
.elisionLines = 1,
|
.elisionLines = 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -510,6 +552,21 @@ void MessageBar::ensureGradientsCreated(int size) {
|
||||||
_topBarGradient = Images::PixmapFast(std::move(top));
|
_topBarGradient = Images::PixmapFast(std::move(top));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageBar::paintImageWithSpoiler(
|
||||||
|
QPainter &p,
|
||||||
|
QRect rect,
|
||||||
|
const QPixmap &image,
|
||||||
|
SpoilerAnimation *spoiler,
|
||||||
|
crl::time now,
|
||||||
|
bool paused) const {
|
||||||
|
p.drawPixmap(rect, image);
|
||||||
|
if (spoiler) {
|
||||||
|
const auto frame = DefaultImageSpoiler().frame(
|
||||||
|
spoiler->index(now, paused));
|
||||||
|
FillSpoilerRect(p, rect, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MessageBar::paintLeftBar(Painter &p) {
|
void MessageBar::paintLeftBar(Painter &p) {
|
||||||
const auto state = countBarState();
|
const auto state = countBarState();
|
||||||
const auto gradientSize = int(std::ceil(state.size * 2.5));
|
const auto gradientSize = int(std::ceil(state.size * 2.5));
|
||||||
|
|
|
@ -18,6 +18,8 @@ struct MessageBar;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
|
class SpoilerAnimation;
|
||||||
|
|
||||||
struct MessageBarContent {
|
struct MessageBarContent {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int count = 1;
|
int count = 1;
|
||||||
|
@ -25,6 +27,7 @@ struct MessageBarContent {
|
||||||
TextWithEntities text;
|
TextWithEntities text;
|
||||||
std::any context;
|
std::any context;
|
||||||
QImage preview;
|
QImage preview;
|
||||||
|
Fn<void()> spoilerRepaint;
|
||||||
style::margins margins;
|
style::margins margins;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,7 +41,7 @@ public:
|
||||||
void set(MessageBarContent &&content);
|
void set(MessageBarContent &&content);
|
||||||
void set(rpl::producer<MessageBarContent> content);
|
void set(rpl::producer<MessageBarContent> content);
|
||||||
|
|
||||||
[[nodiscard]] not_null<Ui::RpWidget*> widget() {
|
[[nodiscard]] not_null<RpWidget*> widget() {
|
||||||
return &_widget;
|
return &_widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,10 +55,10 @@ private:
|
||||||
None,
|
None,
|
||||||
};
|
};
|
||||||
struct Animation {
|
struct Animation {
|
||||||
Ui::Animations::Simple bodyMoved;
|
Animations::Simple bodyMoved;
|
||||||
Ui::Animations::Simple imageShown;
|
Animations::Simple imageShown;
|
||||||
Ui::Animations::Simple barScroll;
|
Animations::Simple barScroll;
|
||||||
Ui::Animations::Simple barTop;
|
Animations::Simple barTop;
|
||||||
QPixmap bodyOrTextFrom;
|
QPixmap bodyOrTextFrom;
|
||||||
QPixmap bodyOrTextTo;
|
QPixmap bodyOrTextTo;
|
||||||
QPixmap titleSame;
|
QPixmap titleSame;
|
||||||
|
@ -63,6 +66,7 @@ private:
|
||||||
QPixmap titleTo;
|
QPixmap titleTo;
|
||||||
QPixmap imageFrom;
|
QPixmap imageFrom;
|
||||||
QPixmap imageTo;
|
QPixmap imageTo;
|
||||||
|
std::unique_ptr<SpoilerAnimation> spoilerFrom;
|
||||||
BodyAnimation bodyAnimation = BodyAnimation::None;
|
BodyAnimation bodyAnimation = BodyAnimation::None;
|
||||||
RectPart movingTo = RectPart::None;
|
RectPart movingTo = RectPart::None;
|
||||||
};
|
};
|
||||||
|
@ -98,19 +102,28 @@ private:
|
||||||
[[nodiscard]] BarState countBarState() const;
|
[[nodiscard]] BarState countBarState() const;
|
||||||
void ensureGradientsCreated(int size);
|
void ensureGradientsCreated(int size);
|
||||||
|
|
||||||
|
void paintImageWithSpoiler(
|
||||||
|
QPainter &p,
|
||||||
|
QRect rect,
|
||||||
|
const QPixmap &image,
|
||||||
|
SpoilerAnimation *spoiler,
|
||||||
|
crl::time now,
|
||||||
|
bool paused) const;
|
||||||
|
|
||||||
[[nodiscard]] static BodyAnimation DetectBodyAnimationType(
|
[[nodiscard]] static BodyAnimation DetectBodyAnimationType(
|
||||||
Animation *currentAnimation,
|
Animation *currentAnimation,
|
||||||
const MessageBarContent ¤tContent,
|
const MessageBarContent ¤tContent,
|
||||||
const MessageBarContent &nextContent);
|
const MessageBarContent &nextContent);
|
||||||
|
|
||||||
const style::MessageBar &_st;
|
const style::MessageBar &_st;
|
||||||
Ui::RpWidget _widget;
|
RpWidget _widget;
|
||||||
Fn<bool()> _customEmojiPaused;
|
Fn<bool()> _customEmojiPaused;
|
||||||
MessageBarContent _content;
|
MessageBarContent _content;
|
||||||
rpl::lifetime _contentLifetime;
|
rpl::lifetime _contentLifetime;
|
||||||
Ui::Text::String _title, _text;
|
Text::String _title, _text;
|
||||||
QPixmap _image, _topBarGradient, _bottomBarGradient;
|
QPixmap _image, _topBarGradient, _bottomBarGradient;
|
||||||
std::unique_ptr<Animation> _animation;
|
std::unique_ptr<Animation> _animation;
|
||||||
|
std::unique_ptr<SpoilerAnimation> _spoiler;
|
||||||
bool _customEmojiRepaintScheduled = false;
|
bool _customEmojiRepaintScheduled = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue