mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 13:17:08 +02:00
Update API scheme to layer 183. Paid media.
This commit is contained in:
parent
e71a067f4b
commit
3ece9b1566
25 changed files with 227 additions and 533 deletions
|
@ -727,8 +727,6 @@ PRIVATE
|
|||
history/view/media/history_view_dice.h
|
||||
history/view/media/history_view_document.cpp
|
||||
history/view/media/history_view_document.h
|
||||
history/view/media/history_view_extended_preview.cpp
|
||||
history/view/media/history_view_extended_preview.h
|
||||
history/view/media/history_view_file.cpp
|
||||
history/view/media/history_view_file.h
|
||||
history/view/media/history_view_game.cpp
|
||||
|
|
|
@ -1696,7 +1696,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
|||
const auto peerId = peerFromMTP(d.vpeer());
|
||||
const auto msgId = d.vmsg_id().v;
|
||||
if (const auto item = session().data().message(peerId, msgId)) {
|
||||
item->applyEdition(d.vextended_media());
|
||||
item->applyEdition(d.vextended_media().v);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "data/data_media_types.h"
|
||||
|
||||
#include "base/random.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h" // CreateMedia.
|
||||
#include "history/history_location_manager.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "history/view/history_view_item_preview.h"
|
||||
#include "history/view/media/history_view_extended_preview.h"
|
||||
#include "history/view/media/history_view_photo.h"
|
||||
#include "history/view/media/history_view_sticker.h"
|
||||
#include "history/view/media/history_view_gif.h"
|
||||
|
@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/media/history_view_giveaway.h"
|
||||
#include "history/view/media/history_view_invoice.h"
|
||||
#include "history/view/media/history_view_media_generic.h"
|
||||
#include "history/view/media/history_view_media_grouped.h"
|
||||
#include "history/view/media/history_view_call.h"
|
||||
#include "history/view/media/history_view_web_page.h"
|
||||
#include "history/view/media/history_view_poll.h"
|
||||
|
@ -261,48 +262,80 @@ template <typename MediaType>
|
|||
}
|
||||
|
||||
bool UpdateExtendedMedia(
|
||||
Invoice &invoice,
|
||||
std::unique_ptr<Media> &media,
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPMessageExtendedMedia &media) {
|
||||
return media.match([&](const MTPDmessageExtendedMediaPreview &data) {
|
||||
if (invoice.extendedMedia) {
|
||||
return false;
|
||||
const MTPMessageExtendedMedia &extended) {
|
||||
return extended.match([&](const MTPDmessageExtendedMediaPreview &data) {
|
||||
auto photo = (PhotoData*)nullptr;
|
||||
if (!media) {
|
||||
const auto id = base::RandomValue<PhotoId>();
|
||||
photo = item->history()->owner().photo(id);
|
||||
} else {
|
||||
photo = media->photo();
|
||||
if (!photo || !photo->extendedMediaPreview()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto changed = false;
|
||||
auto &preview = invoice.extendedPreview;
|
||||
auto size = QSize();
|
||||
auto thumbnail = QByteArray();
|
||||
auto videoDuration = TimeId();
|
||||
if (const auto &w = data.vw()) {
|
||||
const auto &h = data.vh();
|
||||
Assert(h.has_value());
|
||||
const auto dimensions = QSize(w->v, h->v);
|
||||
if (preview.dimensions != dimensions) {
|
||||
preview.dimensions = dimensions;
|
||||
size = QSize(w->v, h->v);
|
||||
if (!changed && photo->size(PhotoSize::Large) != size) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (const auto &thumb = data.vthumb()) {
|
||||
if (thumb->type() == mtpc_photoStrippedSize) {
|
||||
const auto bytes = thumb->c_photoStrippedSize().vbytes().v;
|
||||
if (preview.inlineThumbnailBytes != bytes) {
|
||||
preview.inlineThumbnailBytes = bytes;
|
||||
thumbnail = thumb->c_photoStrippedSize().vbytes().v;
|
||||
if (!changed && photo->inlineThumbnailBytes() != thumbnail) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (const auto &duration = data.vvideo_duration()) {
|
||||
if (preview.videoDuration != duration->v) {
|
||||
preview.videoDuration = duration->v;
|
||||
videoDuration = duration->v;
|
||||
if (photo->extendedMediaVideoDuration() != videoDuration) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
photo->setExtendedMediaPreview(size, thumbnail, videoDuration);
|
||||
}
|
||||
if (!media) {
|
||||
media = std::make_unique<MediaPhoto>(item, photo, true);
|
||||
}
|
||||
return changed;
|
||||
}, [&](const MTPDmessageExtendedMedia &data) {
|
||||
invoice.extendedMedia = HistoryItem::CreateMedia(
|
||||
item,
|
||||
data.vmedia());
|
||||
media = HistoryItem::CreateMedia(item, data.vmedia());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bool UpdateExtendedMedia(
|
||||
Invoice &invoice,
|
||||
not_null<HistoryItem*> item,
|
||||
const QVector<MTPMessageExtendedMedia> &media) {
|
||||
auto changed = false;
|
||||
const auto count = int(media.size());
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
if (i < invoice.extendedMedia.size()) {
|
||||
invoice.extendedMedia.emplace_back();
|
||||
changed = true;
|
||||
}
|
||||
UpdateExtendedMedia(invoice.extendedMedia[i], item, media[i]);
|
||||
}
|
||||
if (count < invoice.extendedMedia.size()) {
|
||||
invoice.extendedMedia.resize(count);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
TextForMimeData WithCaptionClipboardText(
|
||||
const QString &attachType,
|
||||
TextForMimeData &&caption) {
|
||||
|
@ -344,11 +377,22 @@ Invoice ComputeInvoiceData(
|
|||
.isTest = data.is_test(),
|
||||
};
|
||||
if (const auto &media = data.vextended_media()) {
|
||||
UpdateExtendedMedia(result, item, *media);
|
||||
UpdateExtendedMedia(result, item, { *media });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Invoice ComputeInvoiceData(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPDmessageMediaPaidMedia &data) {
|
||||
auto result = Invoice{
|
||||
.amount = data.vstars_amount().v,
|
||||
.currency = Ui::kCreditsCurrency,
|
||||
};
|
||||
UpdateExtendedMedia(result, item, data.vextended_media().v);
|
||||
return result;
|
||||
}
|
||||
|
||||
Call ComputeCallData(const MTPDmessageActionPhoneCall &call) {
|
||||
auto result = Call();
|
||||
result.finishReason = [&] {
|
||||
|
@ -424,6 +468,18 @@ GiveawayResults ComputeGiveawayResultsData(
|
|||
return result;
|
||||
}
|
||||
|
||||
bool HasExtendedMedia(const Invoice &invoice) {
|
||||
return !invoice.extendedMedia.empty();
|
||||
}
|
||||
|
||||
bool HasUnpaidMedia(const Invoice &invoice) {
|
||||
for (const auto &media : invoice.extendedMedia) {
|
||||
const auto photo = media->photo();
|
||||
return photo && photo->extendedMediaPreview();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Media::Media(not_null<HistoryItem*> parent) : _parent(parent) {
|
||||
}
|
||||
|
||||
|
@ -1851,14 +1907,14 @@ MediaInvoice::MediaInvoice(
|
|||
.currency = data.currency,
|
||||
.title = data.title,
|
||||
.description = data.description,
|
||||
.extendedPreview = data.extendedPreview,
|
||||
.extendedMedia = (data.extendedMedia
|
||||
? data.extendedMedia->clone(parent)
|
||||
: nullptr),
|
||||
.photo = data.photo,
|
||||
.isTest = data.isTest,
|
||||
} {
|
||||
if (_invoice.extendedPreview && !_invoice.extendedMedia) {
|
||||
_invoice.extendedMedia.reserve(data.extendedMedia.size());
|
||||
for (auto &item : data.extendedMedia) {
|
||||
_invoice.extendedMedia.push_back(item->clone(parent));
|
||||
}
|
||||
if (HasUnpaidMedia(_invoice)) {
|
||||
Ui::PreloadImageSpoiler();
|
||||
}
|
||||
}
|
||||
|
@ -1917,7 +1973,7 @@ bool MediaInvoice::updateSentMedia(const MTPMessageMedia &media) {
|
|||
|
||||
bool MediaInvoice::updateExtendedMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPMessageExtendedMedia &media) {
|
||||
const QVector<MTPMessageExtendedMedia> &media) {
|
||||
Expects(item == parent());
|
||||
|
||||
return UpdateExtendedMedia(_invoice, item, media);
|
||||
|
@ -1927,15 +1983,15 @@ std::unique_ptr<HistoryView::Media> MediaInvoice::createView(
|
|||
not_null<HistoryView::Element*> message,
|
||||
not_null<HistoryItem*> realParent,
|
||||
HistoryView::Element *replacing) {
|
||||
if (_invoice.extendedMedia) {
|
||||
return _invoice.extendedMedia->createView(
|
||||
if (_invoice.extendedMedia.size() == 1) {
|
||||
return _invoice.extendedMedia.front()->createView(
|
||||
message,
|
||||
realParent,
|
||||
replacing);
|
||||
} else if (_invoice.extendedPreview) {
|
||||
return std::make_unique<HistoryView::ExtendedPreview>(
|
||||
} else if (!_invoice.extendedMedia.empty()) {
|
||||
return std::make_unique<HistoryView::GroupedMedia>(
|
||||
message,
|
||||
&_invoice);
|
||||
_invoice.extendedMedia);
|
||||
}
|
||||
return std::make_unique<HistoryView::Invoice>(message, &_invoice);
|
||||
}
|
||||
|
|
|
@ -84,19 +84,6 @@ struct Call {
|
|||
|
||||
};
|
||||
|
||||
struct ExtendedPreview {
|
||||
QByteArray inlineThumbnailBytes;
|
||||
QSize dimensions;
|
||||
TimeId videoDuration = -1;
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
return dimensions.isEmpty();
|
||||
}
|
||||
explicit operator bool() const {
|
||||
return !empty();
|
||||
}
|
||||
};
|
||||
|
||||
class Media;
|
||||
|
||||
struct Invoice {
|
||||
|
@ -105,11 +92,12 @@ struct Invoice {
|
|||
QString currency;
|
||||
QString title;
|
||||
TextWithEntities description;
|
||||
ExtendedPreview extendedPreview;
|
||||
std::unique_ptr<Media> extendedMedia;
|
||||
std::vector<std::unique_ptr<Media>> extendedMedia;
|
||||
PhotoData *photo = nullptr;
|
||||
bool isTest = false;
|
||||
};
|
||||
[[nodiscard]] bool HasExtendedMedia(const Invoice &invoice);
|
||||
[[nodiscard]] bool HasUnpaidMedia(const Invoice &invoice);
|
||||
|
||||
struct GiveawayStart {
|
||||
std::vector<not_null<ChannelData*>> channels;
|
||||
|
@ -207,7 +195,7 @@ public:
|
|||
virtual bool updateSentMedia(const MTPMessageMedia &media) = 0;
|
||||
virtual bool updateExtendedMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPMessageExtendedMedia &media) {
|
||||
const QVector<MTPMessageExtendedMedia> &media) {
|
||||
return false;
|
||||
}
|
||||
virtual std::unique_ptr<HistoryView::Media> createView(
|
||||
|
@ -524,7 +512,7 @@ public:
|
|||
bool updateSentMedia(const MTPMessageMedia &media) override;
|
||||
bool updateExtendedMedia(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPMessageExtendedMedia &media) override;
|
||||
const QVector<MTPMessageExtendedMedia> &media) override;
|
||||
std::unique_ptr<HistoryView::Media> createView(
|
||||
not_null<HistoryView::Element*> message,
|
||||
not_null<HistoryItem*> realParent,
|
||||
|
@ -750,6 +738,9 @@ private:
|
|||
[[nodiscard]] Invoice ComputeInvoiceData(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPDmessageMediaInvoice &data);
|
||||
[[nodiscard]] Invoice ComputeInvoiceData(
|
||||
not_null<HistoryItem*> item,
|
||||
const MTPDmessageMediaPaidMedia &data);
|
||||
|
||||
[[nodiscard]] Call ComputeCallData(const MTPDmessageActionPhoneCall &call);
|
||||
|
||||
|
|
|
@ -50,6 +50,38 @@ PhotoData::~PhotoData() {
|
|||
base::take(_videoSizes);
|
||||
}
|
||||
|
||||
void PhotoData::setFields(TimeId date, bool hasAttachedStickers) {
|
||||
_dateOrExtendedVideoDuration = date;
|
||||
_hasStickers = hasAttachedStickers;
|
||||
_extendedMediaPreview = false;
|
||||
}
|
||||
|
||||
void PhotoData::setExtendedMediaPreview(
|
||||
QSize dimensions,
|
||||
const QByteArray &inlineThumbnailBytes,
|
||||
TimeId videoDuration) {
|
||||
_extendedMediaPreview = true;
|
||||
updateImages(
|
||||
inlineThumbnailBytes,
|
||||
{},
|
||||
{},
|
||||
{ .location = { {}, dimensions.width(), dimensions.height() } },
|
||||
{},
|
||||
{},
|
||||
{});
|
||||
_dateOrExtendedVideoDuration = videoDuration + 1;
|
||||
}
|
||||
|
||||
bool PhotoData::extendedMediaPreview() const {
|
||||
return _extendedMediaPreview;
|
||||
}
|
||||
|
||||
std::optional<TimeId> PhotoData::extendedMediaVideoDuration() const {
|
||||
return (_extendedMediaPreview && _dateOrExtendedVideoDuration)
|
||||
? TimeId(_dateOrExtendedVideoDuration - 1)
|
||||
: std::optional<TimeId>();
|
||||
}
|
||||
|
||||
Data::Session &PhotoData::owner() const {
|
||||
return *_owner;
|
||||
}
|
||||
|
@ -74,6 +106,10 @@ void PhotoData::load(
|
|||
load(PhotoSize::Large, origin, fromCloud, autoLoading);
|
||||
}
|
||||
|
||||
TimeId PhotoData::date() const {
|
||||
return _extendedMediaPreview ? 0 : _dateOrExtendedVideoDuration;
|
||||
}
|
||||
|
||||
bool PhotoData::loading() const {
|
||||
return loading(PhotoSize::Large);
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
|
||||
void automaticLoadSettingsChanged();
|
||||
|
||||
[[nodiscard]] TimeId date() const;
|
||||
[[nodiscard]] bool loading() const;
|
||||
[[nodiscard]] bool displayLoading() const;
|
||||
void cancel();
|
||||
|
@ -89,6 +90,14 @@ public:
|
|||
[[nodiscard]] auto activeMediaView() const
|
||||
-> std::shared_ptr<Data::PhotoMedia>;
|
||||
|
||||
void setFields(TimeId date, bool hasAttachedStickers);
|
||||
void setExtendedMediaPreview(
|
||||
QSize dimensions,
|
||||
const QByteArray &inlineThumbnailBytes,
|
||||
TimeId videoDuration);
|
||||
[[nodiscard]] bool extendedMediaPreview() const;
|
||||
[[nodiscard]] std::optional<TimeId> extendedMediaVideoDuration() const;
|
||||
|
||||
void updateImages(
|
||||
const QByteArray &inlineThumbnailBytes,
|
||||
const ImageWithLocation &small,
|
||||
|
@ -148,11 +157,10 @@ public:
|
|||
void setHasAttachedStickers(bool value);
|
||||
|
||||
// For now they return size of the 'large' image.
|
||||
int width() const;
|
||||
int height() const;
|
||||
[[nodiscard]] int width() const;
|
||||
[[nodiscard]] int height() const;
|
||||
|
||||
PhotoId id = 0;
|
||||
TimeId date = 0;
|
||||
|
||||
PeerData *peer = nullptr; // for chat and channel photos connection
|
||||
// geo, caption
|
||||
|
@ -164,6 +172,8 @@ private:
|
|||
[[nodiscard]] const Data::CloudFile &videoFile(
|
||||
Data::PhotoSize size) const;
|
||||
|
||||
TimeId _dateOrExtendedVideoDuration = 0;
|
||||
|
||||
struct VideoSizes {
|
||||
Data::CloudFile small;
|
||||
Data::CloudFile large;
|
||||
|
@ -177,6 +187,8 @@ private:
|
|||
int32 _dc = 0;
|
||||
uint64 _access = 0;
|
||||
bool _hasStickers = false;
|
||||
bool _extendedMediaPreview = false;
|
||||
|
||||
QByteArray _fileReference;
|
||||
std::unique_ptr<Data::ReplyPreview> _replyPreview;
|
||||
std::weak_ptr<Data::PhotoMedia> _media;
|
||||
|
|
|
@ -3077,8 +3077,7 @@ void Session::photoApplyFields(
|
|||
return;
|
||||
}
|
||||
photo->setRemoteLocation(dc, access, fileReference);
|
||||
photo->date = date;
|
||||
photo->setHasAttachedStickers(hasStickers);
|
||||
photo->setFields(date, hasStickers);
|
||||
photo->updateImages(
|
||||
inlineThumbnailBytes,
|
||||
small,
|
||||
|
|
|
@ -666,6 +666,28 @@ Invoice ParseInvoice(const MTPDmessageMediaInvoice &data) {
|
|||
return result;
|
||||
}
|
||||
|
||||
PaidMedia ParsePaidMedia(
|
||||
ParseMediaContext &context,
|
||||
const MTPDmessageMediaPaidMedia &data,
|
||||
const QString &folder,
|
||||
TimeId date) {
|
||||
auto result = PaidMedia();
|
||||
result.stars = data.vstars_amount().v;
|
||||
result.extended.reserve(data.vextended_media().v.size());
|
||||
for (const auto &extended : data.vextended_media().v) {
|
||||
result.extended.push_back(extended.match([](
|
||||
const MTPDmessageExtendedMediaPreview &)
|
||||
-> std::unique_ptr<Media> {
|
||||
return std::unique_ptr<Media>();
|
||||
}, [&](const MTPDmessageExtendedMedia &data)
|
||||
-> std::unique_ptr<Media> {
|
||||
return std::make_unique<Media>(
|
||||
ParseMedia(context, data.vmedia(), folder, date));
|
||||
}));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Poll ParsePoll(const MTPDmessageMediaPoll &data) {
|
||||
auto result = Poll();
|
||||
data.vpoll().match([&](const MTPDpoll &poll) {
|
||||
|
@ -1225,6 +1247,8 @@ Media ParseMedia(
|
|||
result.content = ParseGiveaway(data);
|
||||
}, [&](const MTPDmessageMediaGiveawayResults &data) {
|
||||
// #TODO export giveaway
|
||||
}, [&](const MTPDmessageMediaPaidMedia &data) {
|
||||
result.content = ParsePaidMedia(context, data, folder, date);
|
||||
}, [](const MTPDmessageMediaEmpty &data) {});
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -182,6 +182,18 @@ struct Invoice {
|
|||
int32 receiptMsgId = 0;
|
||||
};
|
||||
|
||||
struct Media;
|
||||
struct PaidMedia {
|
||||
PaidMedia() = default;
|
||||
PaidMedia(PaidMedia &&) = default;
|
||||
PaidMedia &operator=(PaidMedia &&) = default;
|
||||
PaidMedia(const PaidMedia &) = delete;
|
||||
PaidMedia &operator=(const PaidMedia &) = delete;
|
||||
|
||||
uint64 stars = 0;
|
||||
std::vector<std::unique_ptr<Media>> extended;
|
||||
};
|
||||
|
||||
struct Poll {
|
||||
struct Answer {
|
||||
Utf8String text;
|
||||
|
@ -337,6 +349,7 @@ struct Media {
|
|||
Invoice,
|
||||
Poll,
|
||||
GiveawayStart,
|
||||
PaidMedia,
|
||||
UnsupportedMedia> content;
|
||||
TimeId ttl = 0;
|
||||
|
||||
|
|
|
@ -2092,6 +2092,9 @@ MediaData HtmlWriter::Wrap::prepareMediaData(
|
|||
result.status = Data::FormatMoneyAmount(data.amount, data.currency);
|
||||
}, [](const Poll &data) {
|
||||
}, [](const GiveawayStart &data) {
|
||||
}, [&](const PaidMedia &data) {
|
||||
result.classes = "media_invoice";
|
||||
result.status = Data::FormatMoneyAmount(data.stars, "XTR");
|
||||
}, [](const UnsupportedMedia &data) {
|
||||
Unexpected("Unsupported message.");
|
||||
}, [](v::null_t) {});
|
||||
|
|
|
@ -779,6 +779,8 @@ QByteArray SerializeMessage(
|
|||
{ "until_date", SerializeDate(data.untilDate) },
|
||||
{ "channels", serialized },
|
||||
}));
|
||||
}, [&](const PaidMedia &data) {
|
||||
push("paid_stars_amount", data.stars);
|
||||
}, [](const UnsupportedMedia &data) {
|
||||
Unexpected("Unsupported message.");
|
||||
}, [](v::null_t) {});
|
||||
|
|
|
@ -1031,7 +1031,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
session().data().reactions().poll(item, context.now);
|
||||
if (item->hasExtendedMediaPreview()) {
|
||||
if (item->hasUnpaidContent()) {
|
||||
session().api().views().pollExtendedMedia(item);
|
||||
}
|
||||
_reactionsManager->recordCurrentReactionEffect(
|
||||
|
|
|
@ -349,6 +349,10 @@ std::unique_ptr<Data::Media> HistoryItem::CreateMedia(
|
|||
return std::make_unique<Data::MediaGiveawayResults>(
|
||||
item,
|
||||
Data::ComputeGiveawayResultsData(item, media));
|
||||
}, [&](const MTPDmessageMediaPaidMedia &media) -> Result {
|
||||
return std::make_unique<Data::MediaInvoice>(
|
||||
item,
|
||||
Data::ComputeInvoiceData(item, media));
|
||||
}, [](const MTPDmessageMediaEmpty &) -> Result {
|
||||
return nullptr;
|
||||
}, [](const MTPDmessageMediaUnsupported &) -> Result {
|
||||
|
@ -1813,7 +1817,8 @@ void HistoryItem::applyEdition(const MTPDmessageService &message) {
|
|||
}
|
||||
}
|
||||
|
||||
void HistoryItem::applyEdition(const MTPMessageExtendedMedia &media) {
|
||||
void HistoryItem::applyEdition(
|
||||
const QVector<MTPMessageExtendedMedia> &media) {
|
||||
if (const auto existing = this->media()) {
|
||||
if (existing->updateExtendedMedia(this, media)) {
|
||||
checkBuyButton();
|
||||
|
@ -2241,7 +2246,7 @@ bool HistoryItem::forbidsSaving() const {
|
|||
if (forbidsForward()) {
|
||||
return true;
|
||||
} else if (const auto invoice = _media ? _media->invoice() : nullptr) {
|
||||
return (invoice->extendedMedia != nullptr);
|
||||
return HasExtendedMedia(*invoice);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -2991,10 +2996,10 @@ bool HistoryItem::externalReply() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool HistoryItem::hasExtendedMediaPreview() const {
|
||||
bool HistoryItem::hasUnpaidContent() const {
|
||||
if (const auto media = _media.get()) {
|
||||
if (const auto invoice = media->invoice()) {
|
||||
return (invoice->extendedPreview && !invoice->extendedMedia);
|
||||
return HasUnpaidMedia(*invoice);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -3778,7 +3783,7 @@ void HistoryItem::createComponents(const MTPDmessage &data) {
|
|||
void HistoryItem::refreshMedia(const MTPMessageMedia *media) {
|
||||
const auto was = (_media != nullptr);
|
||||
if (const auto invoice = was ? _media->invoice() : nullptr) {
|
||||
if (invoice->extendedMedia) {
|
||||
if (HasExtendedMedia(*invoice)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -326,7 +326,7 @@ public:
|
|||
[[nodiscard]] int repliesCount() const;
|
||||
[[nodiscard]] bool repliesAreComments() const;
|
||||
[[nodiscard]] bool externalReply() const;
|
||||
[[nodiscard]] bool hasExtendedMediaPreview() const;
|
||||
[[nodiscard]] bool hasUnpaidContent() const;
|
||||
[[nodiscard]] bool inHighlightProcess() const;
|
||||
void highlightProcessDone();
|
||||
|
||||
|
@ -345,7 +345,7 @@ public:
|
|||
void applyChanges(not_null<Data::Story*> story);
|
||||
|
||||
void applyEdition(const MTPDmessageService &message);
|
||||
void applyEdition(const MTPMessageExtendedMedia &media);
|
||||
void applyEdition(const QVector<MTPMessageExtendedMedia> &media);
|
||||
void updateForwardedInfo(const MTPMessageFwdHeader *fwd);
|
||||
void updateSentContent(
|
||||
const TextWithEntities &textWithEntities,
|
||||
|
|
|
@ -1091,8 +1091,8 @@ void HistoryMessageReplyMarkup::updateData(
|
|||
bool HistoryMessageReplyMarkup::hiddenBy(Data::Media *media) const {
|
||||
if (media && (data.flags & ReplyMarkupFlag::OnlyBuyButton)) {
|
||||
if (const auto invoice = media->invoice()) {
|
||||
if (invoice->extendedPreview
|
||||
&& (!invoice->extendedMedia || !invoice->receiptMsgId)) {
|
||||
if (HasUnpaidMedia(*invoice)
|
||||
|| (HasExtendedMedia(*invoice) && !invoice->receiptMsgId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -557,6 +557,8 @@ MediaCheckResult CheckMessageMedia(const MTPMessageMedia &media) {
|
|||
return Result::Good;
|
||||
}, [](const MTPDmessageMediaGiveawayResults &) {
|
||||
return Result::Good;
|
||||
}, [](const MTPDmessageMediaPaidMedia &) {
|
||||
return Result::Good;
|
||||
}, [](const MTPDmessageMediaUnsupported &) {
|
||||
return Result::Unsupported;
|
||||
});
|
||||
|
|
|
@ -2263,7 +2263,7 @@ void ListWidget::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
session->data().reactions().poll(item, context.now);
|
||||
if (item->hasExtendedMediaPreview()) {
|
||||
if (item->hasUnpaidContent()) {
|
||||
session->api().views().pollExtendedMedia(item);
|
||||
}
|
||||
if (_reactionsManager) {
|
||||
|
|
|
@ -1399,7 +1399,7 @@ CopyRestrictionType ScheduledWidget::listCopyMediaRestrictionType(
|
|||
not_null<HistoryItem*> item) {
|
||||
if (const auto media = item->media()) {
|
||||
if (const auto invoice = media->invoice()) {
|
||||
if (invoice->extendedMedia) {
|
||||
if (HasExtendedMedia(*invoice)) {
|
||||
return CopyMediaRestrictionTypeFor(_history->peer, item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,366 +0,0 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "history/view/media/history_view_extended_preview.h"
|
||||
|
||||
#include "history/history_item.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "history/view/history_view_cursor_state.h"
|
||||
#include "history/view/media/history_view_media_common.h"
|
||||
#include "media/streaming/media_streaming_utility.h"
|
||||
#include "ui/effects/spoiler_mess.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/image/image_prepare.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/power_saving.h"
|
||||
#include "data/data_session.h"
|
||||
#include "payments/payments_checkout_process.h"
|
||||
#include "payments/payments_non_panel_process.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "mainwindow.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
namespace HistoryView {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] ClickHandlerPtr MakeInvoiceLink(not_null<HistoryItem*> item) {
|
||||
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
const auto controller = my.sessionWindow.get();
|
||||
Payments::CheckoutProcess::Start(
|
||||
item,
|
||||
Payments::Mode::Payment,
|
||||
(controller
|
||||
? crl::guard(
|
||||
controller,
|
||||
[=](auto) { controller->widget()->activate(); })
|
||||
: Fn<void(Payments::CheckoutResult)>()),
|
||||
(controller
|
||||
? Payments::ProcessNonPanelPaymentFormFactory(
|
||||
controller,
|
||||
item)
|
||||
: nullptr));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ExtendedPreview::ExtendedPreview(
|
||||
not_null<Element*> parent,
|
||||
not_null<Data::Invoice*> invoice)
|
||||
: Media(parent)
|
||||
, _invoice(invoice) {
|
||||
const auto item = parent->data();
|
||||
_spoiler.link = MakeInvoiceLink(item);
|
||||
resolveButtonText();
|
||||
}
|
||||
|
||||
void ExtendedPreview::resolveButtonText() {
|
||||
if (const auto markup = _parent->data()->inlineReplyMarkup()) {
|
||||
for (const auto &row : markup->data.rows) {
|
||||
for (const auto &button : row) {
|
||||
if (button.type == HistoryMessageMarkupButton::Type::Buy) {
|
||||
_buttonText.setText(
|
||||
st::semiboldTextStyle,
|
||||
TextUtilities::SingleLine(button.text));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExtendedPreview::~ExtendedPreview() {
|
||||
if (hasHeavyPart()) {
|
||||
unloadHeavyPart();
|
||||
_parent->checkHeavyPart();
|
||||
}
|
||||
}
|
||||
|
||||
void ExtendedPreview::ensureThumbnailRead() const {
|
||||
if (!_inlineThumbnail.isNull() || _imageCacheInvalid) {
|
||||
return;
|
||||
}
|
||||
const auto &bytes = _invoice->extendedPreview.inlineThumbnailBytes;
|
||||
if (bytes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
_inlineThumbnail = Images::FromInlineBytes(bytes);
|
||||
if (_inlineThumbnail.isNull()) {
|
||||
_imageCacheInvalid = true;
|
||||
} else {
|
||||
history()->owner().registerHeavyViewPart(_parent);
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtendedPreview::hasHeavyPart() const {
|
||||
return _spoiler.animation || !_inlineThumbnail.isNull();
|
||||
}
|
||||
|
||||
void ExtendedPreview::unloadHeavyPart() {
|
||||
_inlineThumbnail
|
||||
= _spoiler.background
|
||||
= _spoiler.cornerCache
|
||||
= _buttonBackground = QImage();
|
||||
_spoiler.animation = nullptr;
|
||||
}
|
||||
|
||||
bool ExtendedPreview::enforceBubbleWidth() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
QSize ExtendedPreview::countOptimalSize() {
|
||||
const auto &preview = _invoice->extendedPreview;
|
||||
const auto dimensions = preview.dimensions;
|
||||
const auto minWidth = std::min(
|
||||
std::max({
|
||||
_parent->minWidthForMedia(),
|
||||
(_parent->hasBubble()
|
||||
? st::historyPhotoBubbleMinWidth
|
||||
: st::minPhotoSize),
|
||||
minWidthForButton(),
|
||||
}),
|
||||
st::maxMediaSize);
|
||||
const auto scaled = CountDesiredMediaSize(dimensions);
|
||||
auto maxWidth = qMax(scaled.width(), minWidth);
|
||||
auto minHeight = qMax(scaled.height(), st::minPhotoSize);
|
||||
if (preview.videoDuration < 0) {
|
||||
accumulate_max(maxWidth, scaled.height());
|
||||
}
|
||||
return { maxWidth, minHeight };
|
||||
}
|
||||
|
||||
QSize ExtendedPreview::countCurrentSize(int newWidth) {
|
||||
const auto &preview = _invoice->extendedPreview;
|
||||
const auto dimensions = preview.dimensions;
|
||||
const auto thumbMaxWidth = std::min(newWidth, st::maxMediaSize);
|
||||
const auto minWidth = std::min(
|
||||
std::max({
|
||||
_parent->minWidthForMedia(),
|
||||
(_parent->hasBubble()
|
||||
? st::historyPhotoBubbleMinWidth
|
||||
: st::minPhotoSize),
|
||||
minWidthForButton(),
|
||||
}),
|
||||
thumbMaxWidth);
|
||||
const auto scaled = (preview.videoDuration >= 0)
|
||||
? CountMediaSize(
|
||||
CountDesiredMediaSize(dimensions),
|
||||
newWidth)
|
||||
: CountPhotoMediaSize(
|
||||
CountDesiredMediaSize(dimensions),
|
||||
newWidth,
|
||||
maxWidth());
|
||||
newWidth = qMax(scaled.width(), minWidth);
|
||||
auto newHeight = qMax(scaled.height(), st::minPhotoSize);
|
||||
if (_parent->hasBubble()) {
|
||||
const auto maxWithCaption = qMin(
|
||||
st::msgMaxWidth,
|
||||
_parent->textualMaxWidth());
|
||||
newWidth = qMin(qMax(newWidth, maxWithCaption), thumbMaxWidth);
|
||||
}
|
||||
if (newWidth >= maxWidth()) {
|
||||
newHeight = qMin(newHeight, minHeight());
|
||||
}
|
||||
return { newWidth, newHeight };
|
||||
}
|
||||
|
||||
int ExtendedPreview::minWidthForButton() const {
|
||||
return (st::msgBotKbButton.margin + st::msgBotKbButton.padding) * 2
|
||||
+ _buttonText.maxWidth();
|
||||
}
|
||||
|
||||
void ExtendedPreview::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
|
||||
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
||||
auto bubble = _parent->hasBubble();
|
||||
auto rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
|
||||
const auto inWebPage = (_parent->media() != this);
|
||||
const auto rounding = inWebPage
|
||||
? std::optional<Ui::BubbleRounding>()
|
||||
: adjustedBubbleRounding();
|
||||
if (!bubble) {
|
||||
Assert(rounding.has_value());
|
||||
fillImageShadow(p, rthumb, *rounding, context);
|
||||
}
|
||||
validateImageCache(rthumb.size(), rounding);
|
||||
p.drawImage(rthumb.topLeft(), _spoiler.background);
|
||||
fillImageSpoiler(p, &_spoiler, rthumb, context);
|
||||
paintButton(p, rthumb, context);
|
||||
if (context.selected()) {
|
||||
fillImageOverlay(p, rthumb, rounding, context);
|
||||
}
|
||||
|
||||
// date
|
||||
if (!inWebPage) {
|
||||
auto fullRight = paintx + paintw;
|
||||
auto fullBottom = painty + painth;
|
||||
if (needInfoDisplay()) {
|
||||
_parent->drawInfo(
|
||||
p,
|
||||
context,
|
||||
fullRight,
|
||||
fullBottom,
|
||||
2 * paintx + paintw,
|
||||
InfoDisplayType::Image);
|
||||
}
|
||||
if (const auto size = bubble ? std::nullopt : _parent->rightActionSize()) {
|
||||
auto fastShareLeft = _parent->hasRightLayout()
|
||||
? (paintx - size->width() - st::historyFastShareLeft)
|
||||
: (fullRight + st::historyFastShareLeft);
|
||||
auto fastShareTop = (fullBottom - st::historyFastShareBottom - size->height());
|
||||
_parent->drawRightAction(p, context, fastShareLeft, fastShareTop, 2 * paintx + paintw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtendedPreview::validateImageCache(
|
||||
QSize outer,
|
||||
std::optional<Ui::BubbleRounding> rounding) const {
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
if (_spoiler.background.size() == (outer * ratio)
|
||||
&& _spoiler.backgroundRounding == rounding) {
|
||||
return;
|
||||
}
|
||||
_spoiler.background = Images::Round(
|
||||
prepareImageCache(outer),
|
||||
MediaRoundingMask(rounding));
|
||||
_spoiler.backgroundRounding = rounding;
|
||||
}
|
||||
|
||||
QImage ExtendedPreview::prepareImageCache(QSize outer) const {
|
||||
ensureThumbnailRead();
|
||||
return PrepareWithBlurredBackground(outer, {}, {}, _inlineThumbnail);
|
||||
}
|
||||
|
||||
void ExtendedPreview::paintButton(
|
||||
Painter &p,
|
||||
QRect outer,
|
||||
const PaintContext &context) const {
|
||||
const auto st = context.st;
|
||||
const auto &padding = st::extendedPreviewButtonPadding;
|
||||
const auto margin = st::extendedPreviewButtonMargin;
|
||||
const auto width = std::min(
|
||||
_buttonText.maxWidth() + padding.left() + padding.right(),
|
||||
outer.width() - 2 * margin);
|
||||
const auto height = padding.top()
|
||||
+ st::semiboldFont->height
|
||||
+ padding.bottom();
|
||||
const auto overlay = st->msgDateImgBg()->c;
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto size = QSize(width, height);
|
||||
if (_buttonBackground.size() != size * ratio
|
||||
|| _buttonBackgroundOverlay != overlay) {
|
||||
auto &background = _spoiler.background;
|
||||
if (background.width() < width * ratio
|
||||
|| background.height() < height * ratio) {
|
||||
return;
|
||||
}
|
||||
_buttonBackground = background.copy(QRect(
|
||||
(background.width() - width * ratio) / 2,
|
||||
(background.height() - height * ratio) / 2,
|
||||
width * ratio,
|
||||
height * ratio));
|
||||
_buttonBackground.setDevicePixelRatio(ratio);
|
||||
auto p = QPainter(&_buttonBackground);
|
||||
p.fillRect(0, 0, width, height, overlay);
|
||||
p.end();
|
||||
_buttonBackground = Images::Round(
|
||||
std::move(_buttonBackground),
|
||||
Images::CornersMask(height / 2));
|
||||
}
|
||||
const auto left = outer.x() + (outer.width() - width) / 2;
|
||||
const auto top = outer.y() + (outer.height() - height) / 2;
|
||||
p.drawImage(left, top, _buttonBackground);
|
||||
p.setPen(st->msgDateImgFg()->c);
|
||||
_buttonText.drawLeftElided(
|
||||
p,
|
||||
left + padding.left(),
|
||||
top + padding.top(),
|
||||
width - padding.left() - padding.right(),
|
||||
outer.width());
|
||||
}
|
||||
|
||||
TextState ExtendedPreview::textState(QPoint point, StateRequest request) const {
|
||||
auto result = TextState(_parent);
|
||||
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
|
||||
return result;
|
||||
}
|
||||
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
||||
auto bubble = _parent->hasBubble();
|
||||
if (QRect(paintx, painty, paintw, painth).contains(point)) {
|
||||
result.link = _spoiler.link;
|
||||
}
|
||||
if (!bubble && _parent->media() == this) {
|
||||
auto fullRight = paintx + paintw;
|
||||
auto fullBottom = painty + painth;
|
||||
const auto bottomInfoResult = _parent->bottomInfoTextState(
|
||||
fullRight,
|
||||
fullBottom,
|
||||
point,
|
||||
InfoDisplayType::Image);
|
||||
if (bottomInfoResult.link
|
||||
|| bottomInfoResult.cursor != CursorState::None
|
||||
|| bottomInfoResult.customTooltip) {
|
||||
return bottomInfoResult;
|
||||
}
|
||||
if (const auto size = bubble ? std::nullopt : _parent->rightActionSize()) {
|
||||
auto fastShareLeft = _parent->hasRightLayout()
|
||||
? (paintx - size->width() - st::historyFastShareLeft)
|
||||
: (fullRight + st::historyFastShareLeft);
|
||||
auto fastShareTop = (fullBottom - st::historyFastShareBottom - size->height());
|
||||
if (QRect(fastShareLeft, fastShareTop, size->width(), size->height()).contains(point)) {
|
||||
result.link = _parent->rightActionLink(point
|
||||
- QPoint(fastShareLeft, fastShareTop));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ExtendedPreview::toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const {
|
||||
return p == _spoiler.link;
|
||||
}
|
||||
|
||||
bool ExtendedPreview::dragItemByHandler(const ClickHandlerPtr &p) const {
|
||||
return p == _spoiler.link;
|
||||
}
|
||||
|
||||
bool ExtendedPreview::needInfoDisplay() const {
|
||||
return _parent->data()->isSending()
|
||||
|| _parent->data()->hasFailed()
|
||||
|| _parent->isUnderCursor()
|
||||
|| (_parent->delegate()->elementContext() == Context::ChatPreview)
|
||||
|| _parent->isLastAndSelfMessage();
|
||||
}
|
||||
|
||||
bool ExtendedPreview::needsBubble() const {
|
||||
const auto item = _parent->data();
|
||||
return !item->isService()
|
||||
&& (item->repliesAreComments()
|
||||
|| item->externalReply()
|
||||
|| item->viaBot()
|
||||
|| !item->emptyText()
|
||||
|| _parent->displayReply()
|
||||
|| _parent->displayForwardedFrom()
|
||||
|| _parent->displayFromName()
|
||||
|| _parent->displayedTopicButton());
|
||||
}
|
||||
|
||||
QPoint ExtendedPreview::resolveCustomInfoRightBottom() const {
|
||||
const auto skipx = (st::msgDateImgDelta + st::msgDateImgPadding.x());
|
||||
const auto skipy = (st::msgDateImgDelta + st::msgDateImgPadding.y());
|
||||
return QPoint(width() - skipx, height() - skipy);
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "history/view/media/history_view_media.h"
|
||||
#include "history/view/media/history_view_media_spoiler.h"
|
||||
|
||||
enum class ImageRoundRadius;
|
||||
|
||||
namespace Ui {
|
||||
class SpoilerAnimation;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Data {
|
||||
struct Invoice;
|
||||
} // namespace Data
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
class Element;
|
||||
|
||||
class ExtendedPreview final : public Media {
|
||||
public:
|
||||
ExtendedPreview(
|
||||
not_null<Element*> parent,
|
||||
not_null<Data::Invoice*> invoice);
|
||||
~ExtendedPreview();
|
||||
|
||||
bool hideMessageText() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
[[nodiscard]] bool toggleSelectionByHandlerClick(
|
||||
const ClickHandlerPtr &p) const override;
|
||||
[[nodiscard]] bool dragItemByHandler(
|
||||
const ClickHandlerPtr &p) const override;
|
||||
|
||||
bool needsBubble() const override;
|
||||
bool customInfoLayout() const override {
|
||||
return true;
|
||||
}
|
||||
QPoint resolveCustomInfoRightBottom() const override;
|
||||
bool skipBubbleTail() const override {
|
||||
return isRoundedInBubbleBottom();
|
||||
}
|
||||
|
||||
bool hasHeavyPart() const override;
|
||||
void unloadHeavyPart() override;
|
||||
bool enforceBubbleWidth() const override;
|
||||
|
||||
private:
|
||||
int minWidthForButton() const;
|
||||
void resolveButtonText();
|
||||
void ensureThumbnailRead() const;
|
||||
|
||||
QSize countOptimalSize() override;
|
||||
QSize countCurrentSize(int newWidth) override;
|
||||
|
||||
bool needInfoDisplay() const;
|
||||
void validateImageCache(
|
||||
QSize outer,
|
||||
std::optional<Ui::BubbleRounding> rounding) const;
|
||||
[[nodiscard]] QImage prepareImageCache(QSize outer) const;
|
||||
void paintButton(
|
||||
Painter &p,
|
||||
QRect outer,
|
||||
const PaintContext &context) const;
|
||||
|
||||
const not_null<Data::Invoice*> _invoice;
|
||||
mutable MediaSpoiler _spoiler;
|
||||
mutable QImage _inlineThumbnail;
|
||||
mutable QImage _buttonBackground;
|
||||
mutable QColor _buttonBackgroundOverlay;
|
||||
mutable Ui::Text::String _buttonText;
|
||||
mutable bool _imageCacheInvalid = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace HistoryView
|
|
@ -219,10 +219,14 @@ QSize Photo::countCurrentSize(int newWidth) {
|
|||
: st::minPhotoSize),
|
||||
thumbMaxWidth);
|
||||
const auto dimensions = photoSize();
|
||||
auto pix = CountPhotoMediaSize(
|
||||
CountDesiredMediaSize(dimensions),
|
||||
newWidth,
|
||||
maxWidth());
|
||||
auto pix = _data->extendedMediaVideoDuration()
|
||||
? CountMediaSize(
|
||||
CountDesiredMediaSize(dimensions),
|
||||
newWidth)
|
||||
: CountPhotoMediaSize(
|
||||
CountDesiredMediaSize(dimensions),
|
||||
newWidth,
|
||||
maxWidth());
|
||||
newWidth = qMax(pix.width(), minWidth);
|
||||
auto newHeight = qMax(pix.height(), st::minPhotoSize);
|
||||
if (_parent->hasBubble()) {
|
||||
|
|
|
@ -1362,7 +1362,7 @@ void OverlayWidget::updateControls() {
|
|||
if (_message) {
|
||||
return ItemDateTime(_message);
|
||||
} else if (_photo) {
|
||||
return base::unixtime::parse(_photo->date);
|
||||
return base::unixtime::parse(_photo->date());
|
||||
} else if (_document) {
|
||||
return base::unixtime::parse(_document->date);
|
||||
}
|
||||
|
@ -2436,7 +2436,7 @@ void OverlayWidget::saveAs() {
|
|||
u".mp4"_q,
|
||||
QString(),
|
||||
false,
|
||||
_photo->date),
|
||||
_photo->date()),
|
||||
crl::guard(_window, [=](const QString &result) {
|
||||
QFile f(result);
|
||||
if (!result.isEmpty()
|
||||
|
@ -2467,7 +2467,7 @@ void OverlayWidget::saveAs() {
|
|||
u".jpg"_q,
|
||||
QString(),
|
||||
false,
|
||||
_photo->date),
|
||||
_photo->date()),
|
||||
crl::guard(_window, [=](const QString &result) {
|
||||
if (!result.isEmpty() && _photo == photo) {
|
||||
media->saveToFile(result);
|
||||
|
|
|
@ -44,6 +44,7 @@ inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> s
|
|||
inputMediaDice#e66fbf7b emoticon:string = InputMedia;
|
||||
inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia;
|
||||
inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia;
|
||||
inputMediaPaidMedia#aa661fc3 stars_amount:long extended_media:Vector<InputMedia> = InputMedia;
|
||||
|
||||
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
|
||||
inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto;
|
||||
|
@ -133,6 +134,7 @@ messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
|
|||
messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia;
|
||||
messageMediaGiveaway#daad85b0 flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:int until_date:int = MessageMedia;
|
||||
messageMediaGiveawayResults#c6991068 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:int prize_description:flags.1?string until_date:int = MessageMedia;
|
||||
messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector<MessageExtendedMedia> = MessageMedia;
|
||||
|
||||
messageActionEmpty#b6aef7b0 = MessageAction;
|
||||
messageActionChatCreate#bd47cbad title:string users:Vector<long> = MessageAction;
|
||||
|
@ -384,7 +386,7 @@ updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update;
|
|||
updateRecentEmojiStatuses#30f443db = Update;
|
||||
updateRecentReactions#6f7863f4 = Update;
|
||||
updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update;
|
||||
updateMessageExtendedMedia#5a73a98c peer:Peer msg_id:int extended_media:MessageExtendedMedia = Update;
|
||||
updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector<MessageExtendedMedia> = Update;
|
||||
updateChannelPinnedTopic#192efbe3 flags:# pinned:flags.0?true channel_id:long topic_id:int = Update;
|
||||
updateChannelPinnedTopics#fe198602 flags:# channel_id:long order:flags.0?Vector<int> = Update;
|
||||
updateUser#20529438 user_id:long = Update;
|
||||
|
@ -1806,7 +1808,7 @@ starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer;
|
|||
|
||||
starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption;
|
||||
|
||||
starsTransaction#aa00c898 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string = StarsTransaction;
|
||||
starsTransaction#2db5418f flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true id:string stars:long date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector<MessageMedia> = StarsTransaction;
|
||||
|
||||
payments.starsStatus#8cf4ee60 flags:# balance:long history:Vector<StarsTransaction> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = payments.StarsStatus;
|
||||
|
||||
|
@ -2488,4 +2490,4 @@ smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool;
|
|||
|
||||
fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;
|
||||
|
||||
// LAYER 182
|
||||
// LAYER 183
|
||||
|
|
|
@ -968,7 +968,7 @@ CopyRestrictionType ShortcutMessages::listCopyMediaRestrictionType(
|
|||
not_null<HistoryItem*> item) {
|
||||
if (const auto media = item->media()) {
|
||||
if (const auto invoice = media->invoice()) {
|
||||
if (invoice->extendedMedia) {
|
||||
if (!invoice->extendedMedia.empty()) {
|
||||
return CopyMediaRestrictionTypeFor(_history->peer, item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -416,7 +416,7 @@ void UserpicButton::openPeerPhoto() {
|
|||
return;
|
||||
}
|
||||
const auto photo = _peer->owner().photo(id);
|
||||
if (photo->date && _controller) {
|
||||
if (photo->date() && _controller) {
|
||||
_controller->openPhoto(photo, _peer);
|
||||
}
|
||||
}
|
||||
|
@ -744,7 +744,7 @@ void UserpicButton::updateVideo() {
|
|||
return;
|
||||
}
|
||||
const auto photo = _peer->owner().photo(id);
|
||||
if (!photo->date || !photo->videoCanBePlayed()) {
|
||||
if (!photo->date() || !photo->videoCanBePlayed()) {
|
||||
clearStreaming();
|
||||
return;
|
||||
} else if (_streamed && _streamedPhoto == photo) {
|
||||
|
|
Loading…
Add table
Reference in a new issue