mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-03 21:54:05 +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_dice.h
|
||||||
history/view/media/history_view_document.cpp
|
history/view/media/history_view_document.cpp
|
||||||
history/view/media/history_view_document.h
|
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.cpp
|
||||||
history/view/media/history_view_file.h
|
history/view/media/history_view_file.h
|
||||||
history/view/media/history_view_game.cpp
|
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 peerId = peerFromMTP(d.vpeer());
|
||||||
const auto msgId = d.vmsg_id().v;
|
const auto msgId = d.vmsg_id().v;
|
||||||
if (const auto item = session().data().message(peerId, msgId)) {
|
if (const auto item = session().data().message(peerId, msgId)) {
|
||||||
item->applyEdition(d.vextended_media());
|
item->applyEdition(d.vextended_media().v);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
|
|
||||||
|
#include "base/random.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h" // CreateMedia.
|
#include "history/history_item.h" // CreateMedia.
|
||||||
#include "history/history_location_manager.h"
|
#include "history/history_location_manager.h"
|
||||||
#include "history/view/history_view_element.h"
|
#include "history/view/history_view_element.h"
|
||||||
#include "history/view/history_view_item_preview.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_photo.h"
|
||||||
#include "history/view/media/history_view_sticker.h"
|
#include "history/view/media/history_view_sticker.h"
|
||||||
#include "history/view/media/history_view_gif.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_giveaway.h"
|
||||||
#include "history/view/media/history_view_invoice.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_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_call.h"
|
||||||
#include "history/view/media/history_view_web_page.h"
|
#include "history/view/media/history_view_web_page.h"
|
||||||
#include "history/view/media/history_view_poll.h"
|
#include "history/view/media/history_view_poll.h"
|
||||||
|
@ -261,48 +262,80 @@ template <typename MediaType>
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdateExtendedMedia(
|
bool UpdateExtendedMedia(
|
||||||
Invoice &invoice,
|
std::unique_ptr<Media> &media,
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
const MTPMessageExtendedMedia &media) {
|
const MTPMessageExtendedMedia &extended) {
|
||||||
return media.match([&](const MTPDmessageExtendedMediaPreview &data) {
|
return extended.match([&](const MTPDmessageExtendedMediaPreview &data) {
|
||||||
if (invoice.extendedMedia) {
|
auto photo = (PhotoData*)nullptr;
|
||||||
return false;
|
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 changed = false;
|
||||||
auto &preview = invoice.extendedPreview;
|
auto size = QSize();
|
||||||
|
auto thumbnail = QByteArray();
|
||||||
|
auto videoDuration = TimeId();
|
||||||
if (const auto &w = data.vw()) {
|
if (const auto &w = data.vw()) {
|
||||||
const auto &h = data.vh();
|
const auto &h = data.vh();
|
||||||
Assert(h.has_value());
|
Assert(h.has_value());
|
||||||
const auto dimensions = QSize(w->v, h->v);
|
size = QSize(w->v, h->v);
|
||||||
if (preview.dimensions != dimensions) {
|
if (!changed && photo->size(PhotoSize::Large) != size) {
|
||||||
preview.dimensions = dimensions;
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (const auto &thumb = data.vthumb()) {
|
if (const auto &thumb = data.vthumb()) {
|
||||||
if (thumb->type() == mtpc_photoStrippedSize) {
|
if (thumb->type() == mtpc_photoStrippedSize) {
|
||||||
const auto bytes = thumb->c_photoStrippedSize().vbytes().v;
|
thumbnail = thumb->c_photoStrippedSize().vbytes().v;
|
||||||
if (preview.inlineThumbnailBytes != bytes) {
|
if (!changed && photo->inlineThumbnailBytes() != thumbnail) {
|
||||||
preview.inlineThumbnailBytes = bytes;
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (const auto &duration = data.vvideo_duration()) {
|
if (const auto &duration = data.vvideo_duration()) {
|
||||||
if (preview.videoDuration != duration->v) {
|
videoDuration = duration->v;
|
||||||
preview.videoDuration = duration->v;
|
if (photo->extendedMediaVideoDuration() != videoDuration) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (changed) {
|
||||||
|
photo->setExtendedMediaPreview(size, thumbnail, videoDuration);
|
||||||
|
}
|
||||||
|
if (!media) {
|
||||||
|
media = std::make_unique<MediaPhoto>(item, photo, true);
|
||||||
|
}
|
||||||
return changed;
|
return changed;
|
||||||
}, [&](const MTPDmessageExtendedMedia &data) {
|
}, [&](const MTPDmessageExtendedMedia &data) {
|
||||||
invoice.extendedMedia = HistoryItem::CreateMedia(
|
media = HistoryItem::CreateMedia(item, data.vmedia());
|
||||||
item,
|
|
||||||
data.vmedia());
|
|
||||||
return true;
|
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(
|
TextForMimeData WithCaptionClipboardText(
|
||||||
const QString &attachType,
|
const QString &attachType,
|
||||||
TextForMimeData &&caption) {
|
TextForMimeData &&caption) {
|
||||||
|
@ -344,11 +377,22 @@ Invoice ComputeInvoiceData(
|
||||||
.isTest = data.is_test(),
|
.isTest = data.is_test(),
|
||||||
};
|
};
|
||||||
if (const auto &media = data.vextended_media()) {
|
if (const auto &media = data.vextended_media()) {
|
||||||
UpdateExtendedMedia(result, item, *media);
|
UpdateExtendedMedia(result, item, { *media });
|
||||||
}
|
}
|
||||||
return result;
|
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) {
|
Call ComputeCallData(const MTPDmessageActionPhoneCall &call) {
|
||||||
auto result = Call();
|
auto result = Call();
|
||||||
result.finishReason = [&] {
|
result.finishReason = [&] {
|
||||||
|
@ -424,6 +468,18 @@ GiveawayResults ComputeGiveawayResultsData(
|
||||||
return result;
|
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) {
|
Media::Media(not_null<HistoryItem*> parent) : _parent(parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1851,14 +1907,14 @@ MediaInvoice::MediaInvoice(
|
||||||
.currency = data.currency,
|
.currency = data.currency,
|
||||||
.title = data.title,
|
.title = data.title,
|
||||||
.description = data.description,
|
.description = data.description,
|
||||||
.extendedPreview = data.extendedPreview,
|
|
||||||
.extendedMedia = (data.extendedMedia
|
|
||||||
? data.extendedMedia->clone(parent)
|
|
||||||
: nullptr),
|
|
||||||
.photo = data.photo,
|
.photo = data.photo,
|
||||||
.isTest = data.isTest,
|
.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();
|
Ui::PreloadImageSpoiler();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1917,7 +1973,7 @@ bool MediaInvoice::updateSentMedia(const MTPMessageMedia &media) {
|
||||||
|
|
||||||
bool MediaInvoice::updateExtendedMedia(
|
bool MediaInvoice::updateExtendedMedia(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
const MTPMessageExtendedMedia &media) {
|
const QVector<MTPMessageExtendedMedia> &media) {
|
||||||
Expects(item == parent());
|
Expects(item == parent());
|
||||||
|
|
||||||
return UpdateExtendedMedia(_invoice, item, media);
|
return UpdateExtendedMedia(_invoice, item, media);
|
||||||
|
@ -1927,15 +1983,15 @@ std::unique_ptr<HistoryView::Media> MediaInvoice::createView(
|
||||||
not_null<HistoryView::Element*> message,
|
not_null<HistoryView::Element*> message,
|
||||||
not_null<HistoryItem*> realParent,
|
not_null<HistoryItem*> realParent,
|
||||||
HistoryView::Element *replacing) {
|
HistoryView::Element *replacing) {
|
||||||
if (_invoice.extendedMedia) {
|
if (_invoice.extendedMedia.size() == 1) {
|
||||||
return _invoice.extendedMedia->createView(
|
return _invoice.extendedMedia.front()->createView(
|
||||||
message,
|
message,
|
||||||
realParent,
|
realParent,
|
||||||
replacing);
|
replacing);
|
||||||
} else if (_invoice.extendedPreview) {
|
} else if (!_invoice.extendedMedia.empty()) {
|
||||||
return std::make_unique<HistoryView::ExtendedPreview>(
|
return std::make_unique<HistoryView::GroupedMedia>(
|
||||||
message,
|
message,
|
||||||
&_invoice);
|
_invoice.extendedMedia);
|
||||||
}
|
}
|
||||||
return std::make_unique<HistoryView::Invoice>(message, &_invoice);
|
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;
|
class Media;
|
||||||
|
|
||||||
struct Invoice {
|
struct Invoice {
|
||||||
|
@ -105,11 +92,12 @@ struct Invoice {
|
||||||
QString currency;
|
QString currency;
|
||||||
QString title;
|
QString title;
|
||||||
TextWithEntities description;
|
TextWithEntities description;
|
||||||
ExtendedPreview extendedPreview;
|
std::vector<std::unique_ptr<Media>> extendedMedia;
|
||||||
std::unique_ptr<Media> extendedMedia;
|
|
||||||
PhotoData *photo = nullptr;
|
PhotoData *photo = nullptr;
|
||||||
bool isTest = false;
|
bool isTest = false;
|
||||||
};
|
};
|
||||||
|
[[nodiscard]] bool HasExtendedMedia(const Invoice &invoice);
|
||||||
|
[[nodiscard]] bool HasUnpaidMedia(const Invoice &invoice);
|
||||||
|
|
||||||
struct GiveawayStart {
|
struct GiveawayStart {
|
||||||
std::vector<not_null<ChannelData*>> channels;
|
std::vector<not_null<ChannelData*>> channels;
|
||||||
|
@ -207,7 +195,7 @@ public:
|
||||||
virtual bool updateSentMedia(const MTPMessageMedia &media) = 0;
|
virtual bool updateSentMedia(const MTPMessageMedia &media) = 0;
|
||||||
virtual bool updateExtendedMedia(
|
virtual bool updateExtendedMedia(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
const MTPMessageExtendedMedia &media) {
|
const QVector<MTPMessageExtendedMedia> &media) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
virtual std::unique_ptr<HistoryView::Media> createView(
|
virtual std::unique_ptr<HistoryView::Media> createView(
|
||||||
|
@ -524,7 +512,7 @@ public:
|
||||||
bool updateSentMedia(const MTPMessageMedia &media) override;
|
bool updateSentMedia(const MTPMessageMedia &media) override;
|
||||||
bool updateExtendedMedia(
|
bool updateExtendedMedia(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
const MTPMessageExtendedMedia &media) override;
|
const QVector<MTPMessageExtendedMedia> &media) override;
|
||||||
std::unique_ptr<HistoryView::Media> createView(
|
std::unique_ptr<HistoryView::Media> createView(
|
||||||
not_null<HistoryView::Element*> message,
|
not_null<HistoryView::Element*> message,
|
||||||
not_null<HistoryItem*> realParent,
|
not_null<HistoryItem*> realParent,
|
||||||
|
@ -750,6 +738,9 @@ private:
|
||||||
[[nodiscard]] Invoice ComputeInvoiceData(
|
[[nodiscard]] Invoice ComputeInvoiceData(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
const MTPDmessageMediaInvoice &data);
|
const MTPDmessageMediaInvoice &data);
|
||||||
|
[[nodiscard]] Invoice ComputeInvoiceData(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
const MTPDmessageMediaPaidMedia &data);
|
||||||
|
|
||||||
[[nodiscard]] Call ComputeCallData(const MTPDmessageActionPhoneCall &call);
|
[[nodiscard]] Call ComputeCallData(const MTPDmessageActionPhoneCall &call);
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,38 @@ PhotoData::~PhotoData() {
|
||||||
base::take(_videoSizes);
|
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 {
|
Data::Session &PhotoData::owner() const {
|
||||||
return *_owner;
|
return *_owner;
|
||||||
}
|
}
|
||||||
|
@ -74,6 +106,10 @@ void PhotoData::load(
|
||||||
load(PhotoSize::Large, origin, fromCloud, autoLoading);
|
load(PhotoSize::Large, origin, fromCloud, autoLoading);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimeId PhotoData::date() const {
|
||||||
|
return _extendedMediaPreview ? 0 : _dateOrExtendedVideoDuration;
|
||||||
|
}
|
||||||
|
|
||||||
bool PhotoData::loading() const {
|
bool PhotoData::loading() const {
|
||||||
return loading(PhotoSize::Large);
|
return loading(PhotoSize::Large);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ public:
|
||||||
|
|
||||||
void automaticLoadSettingsChanged();
|
void automaticLoadSettingsChanged();
|
||||||
|
|
||||||
|
[[nodiscard]] TimeId date() const;
|
||||||
[[nodiscard]] bool loading() const;
|
[[nodiscard]] bool loading() const;
|
||||||
[[nodiscard]] bool displayLoading() const;
|
[[nodiscard]] bool displayLoading() const;
|
||||||
void cancel();
|
void cancel();
|
||||||
|
@ -89,6 +90,14 @@ public:
|
||||||
[[nodiscard]] auto activeMediaView() const
|
[[nodiscard]] auto activeMediaView() const
|
||||||
-> std::shared_ptr<Data::PhotoMedia>;
|
-> 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(
|
void updateImages(
|
||||||
const QByteArray &inlineThumbnailBytes,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
const ImageWithLocation &small,
|
const ImageWithLocation &small,
|
||||||
|
@ -148,11 +157,10 @@ public:
|
||||||
void setHasAttachedStickers(bool value);
|
void setHasAttachedStickers(bool value);
|
||||||
|
|
||||||
// For now they return size of the 'large' image.
|
// For now they return size of the 'large' image.
|
||||||
int width() const;
|
[[nodiscard]] int width() const;
|
||||||
int height() const;
|
[[nodiscard]] int height() const;
|
||||||
|
|
||||||
PhotoId id = 0;
|
PhotoId id = 0;
|
||||||
TimeId date = 0;
|
|
||||||
|
|
||||||
PeerData *peer = nullptr; // for chat and channel photos connection
|
PeerData *peer = nullptr; // for chat and channel photos connection
|
||||||
// geo, caption
|
// geo, caption
|
||||||
|
@ -164,6 +172,8 @@ private:
|
||||||
[[nodiscard]] const Data::CloudFile &videoFile(
|
[[nodiscard]] const Data::CloudFile &videoFile(
|
||||||
Data::PhotoSize size) const;
|
Data::PhotoSize size) const;
|
||||||
|
|
||||||
|
TimeId _dateOrExtendedVideoDuration = 0;
|
||||||
|
|
||||||
struct VideoSizes {
|
struct VideoSizes {
|
||||||
Data::CloudFile small;
|
Data::CloudFile small;
|
||||||
Data::CloudFile large;
|
Data::CloudFile large;
|
||||||
|
@ -177,6 +187,8 @@ private:
|
||||||
int32 _dc = 0;
|
int32 _dc = 0;
|
||||||
uint64 _access = 0;
|
uint64 _access = 0;
|
||||||
bool _hasStickers = false;
|
bool _hasStickers = false;
|
||||||
|
bool _extendedMediaPreview = false;
|
||||||
|
|
||||||
QByteArray _fileReference;
|
QByteArray _fileReference;
|
||||||
std::unique_ptr<Data::ReplyPreview> _replyPreview;
|
std::unique_ptr<Data::ReplyPreview> _replyPreview;
|
||||||
std::weak_ptr<Data::PhotoMedia> _media;
|
std::weak_ptr<Data::PhotoMedia> _media;
|
||||||
|
|
|
@ -3077,8 +3077,7 @@ void Session::photoApplyFields(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
photo->setRemoteLocation(dc, access, fileReference);
|
photo->setRemoteLocation(dc, access, fileReference);
|
||||||
photo->date = date;
|
photo->setFields(date, hasStickers);
|
||||||
photo->setHasAttachedStickers(hasStickers);
|
|
||||||
photo->updateImages(
|
photo->updateImages(
|
||||||
inlineThumbnailBytes,
|
inlineThumbnailBytes,
|
||||||
small,
|
small,
|
||||||
|
|
|
@ -666,6 +666,28 @@ Invoice ParseInvoice(const MTPDmessageMediaInvoice &data) {
|
||||||
return result;
|
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) {
|
Poll ParsePoll(const MTPDmessageMediaPoll &data) {
|
||||||
auto result = Poll();
|
auto result = Poll();
|
||||||
data.vpoll().match([&](const MTPDpoll &poll) {
|
data.vpoll().match([&](const MTPDpoll &poll) {
|
||||||
|
@ -1225,6 +1247,8 @@ Media ParseMedia(
|
||||||
result.content = ParseGiveaway(data);
|
result.content = ParseGiveaway(data);
|
||||||
}, [&](const MTPDmessageMediaGiveawayResults &data) {
|
}, [&](const MTPDmessageMediaGiveawayResults &data) {
|
||||||
// #TODO export giveaway
|
// #TODO export giveaway
|
||||||
|
}, [&](const MTPDmessageMediaPaidMedia &data) {
|
||||||
|
result.content = ParsePaidMedia(context, data, folder, date);
|
||||||
}, [](const MTPDmessageMediaEmpty &data) {});
|
}, [](const MTPDmessageMediaEmpty &data) {});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,6 +182,18 @@ struct Invoice {
|
||||||
int32 receiptMsgId = 0;
|
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 Poll {
|
||||||
struct Answer {
|
struct Answer {
|
||||||
Utf8String text;
|
Utf8String text;
|
||||||
|
@ -337,6 +349,7 @@ struct Media {
|
||||||
Invoice,
|
Invoice,
|
||||||
Poll,
|
Poll,
|
||||||
GiveawayStart,
|
GiveawayStart,
|
||||||
|
PaidMedia,
|
||||||
UnsupportedMedia> content;
|
UnsupportedMedia> content;
|
||||||
TimeId ttl = 0;
|
TimeId ttl = 0;
|
||||||
|
|
||||||
|
|
|
@ -2092,6 +2092,9 @@ MediaData HtmlWriter::Wrap::prepareMediaData(
|
||||||
result.status = Data::FormatMoneyAmount(data.amount, data.currency);
|
result.status = Data::FormatMoneyAmount(data.amount, data.currency);
|
||||||
}, [](const Poll &data) {
|
}, [](const Poll &data) {
|
||||||
}, [](const GiveawayStart &data) {
|
}, [](const GiveawayStart &data) {
|
||||||
|
}, [&](const PaidMedia &data) {
|
||||||
|
result.classes = "media_invoice";
|
||||||
|
result.status = Data::FormatMoneyAmount(data.stars, "XTR");
|
||||||
}, [](const UnsupportedMedia &data) {
|
}, [](const UnsupportedMedia &data) {
|
||||||
Unexpected("Unsupported message.");
|
Unexpected("Unsupported message.");
|
||||||
}, [](v::null_t) {});
|
}, [](v::null_t) {});
|
||||||
|
|
|
@ -779,6 +779,8 @@ QByteArray SerializeMessage(
|
||||||
{ "until_date", SerializeDate(data.untilDate) },
|
{ "until_date", SerializeDate(data.untilDate) },
|
||||||
{ "channels", serialized },
|
{ "channels", serialized },
|
||||||
}));
|
}));
|
||||||
|
}, [&](const PaidMedia &data) {
|
||||||
|
push("paid_stars_amount", data.stars);
|
||||||
}, [](const UnsupportedMedia &data) {
|
}, [](const UnsupportedMedia &data) {
|
||||||
Unexpected("Unsupported message.");
|
Unexpected("Unsupported message.");
|
||||||
}, [](v::null_t) {});
|
}, [](v::null_t) {});
|
||||||
|
|
|
@ -1031,7 +1031,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session().data().reactions().poll(item, context.now);
|
session().data().reactions().poll(item, context.now);
|
||||||
if (item->hasExtendedMediaPreview()) {
|
if (item->hasUnpaidContent()) {
|
||||||
session().api().views().pollExtendedMedia(item);
|
session().api().views().pollExtendedMedia(item);
|
||||||
}
|
}
|
||||||
_reactionsManager->recordCurrentReactionEffect(
|
_reactionsManager->recordCurrentReactionEffect(
|
||||||
|
|
|
@ -349,6 +349,10 @@ std::unique_ptr<Data::Media> HistoryItem::CreateMedia(
|
||||||
return std::make_unique<Data::MediaGiveawayResults>(
|
return std::make_unique<Data::MediaGiveawayResults>(
|
||||||
item,
|
item,
|
||||||
Data::ComputeGiveawayResultsData(item, media));
|
Data::ComputeGiveawayResultsData(item, media));
|
||||||
|
}, [&](const MTPDmessageMediaPaidMedia &media) -> Result {
|
||||||
|
return std::make_unique<Data::MediaInvoice>(
|
||||||
|
item,
|
||||||
|
Data::ComputeInvoiceData(item, media));
|
||||||
}, [](const MTPDmessageMediaEmpty &) -> Result {
|
}, [](const MTPDmessageMediaEmpty &) -> Result {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}, [](const MTPDmessageMediaUnsupported &) -> Result {
|
}, [](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 (const auto existing = this->media()) {
|
||||||
if (existing->updateExtendedMedia(this, media)) {
|
if (existing->updateExtendedMedia(this, media)) {
|
||||||
checkBuyButton();
|
checkBuyButton();
|
||||||
|
@ -2241,7 +2246,7 @@ bool HistoryItem::forbidsSaving() const {
|
||||||
if (forbidsForward()) {
|
if (forbidsForward()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (const auto invoice = _media ? _media->invoice() : nullptr) {
|
} else if (const auto invoice = _media ? _media->invoice() : nullptr) {
|
||||||
return (invoice->extendedMedia != nullptr);
|
return HasExtendedMedia(*invoice);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2991,10 +2996,10 @@ bool HistoryItem::externalReply() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryItem::hasExtendedMediaPreview() const {
|
bool HistoryItem::hasUnpaidContent() const {
|
||||||
if (const auto media = _media.get()) {
|
if (const auto media = _media.get()) {
|
||||||
if (const auto invoice = media->invoice()) {
|
if (const auto invoice = media->invoice()) {
|
||||||
return (invoice->extendedPreview && !invoice->extendedMedia);
|
return HasUnpaidMedia(*invoice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -3778,7 +3783,7 @@ void HistoryItem::createComponents(const MTPDmessage &data) {
|
||||||
void HistoryItem::refreshMedia(const MTPMessageMedia *media) {
|
void HistoryItem::refreshMedia(const MTPMessageMedia *media) {
|
||||||
const auto was = (_media != nullptr);
|
const auto was = (_media != nullptr);
|
||||||
if (const auto invoice = was ? _media->invoice() : nullptr) {
|
if (const auto invoice = was ? _media->invoice() : nullptr) {
|
||||||
if (invoice->extendedMedia) {
|
if (HasExtendedMedia(*invoice)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -326,7 +326,7 @@ public:
|
||||||
[[nodiscard]] int repliesCount() const;
|
[[nodiscard]] int repliesCount() const;
|
||||||
[[nodiscard]] bool repliesAreComments() const;
|
[[nodiscard]] bool repliesAreComments() const;
|
||||||
[[nodiscard]] bool externalReply() const;
|
[[nodiscard]] bool externalReply() const;
|
||||||
[[nodiscard]] bool hasExtendedMediaPreview() const;
|
[[nodiscard]] bool hasUnpaidContent() const;
|
||||||
[[nodiscard]] bool inHighlightProcess() const;
|
[[nodiscard]] bool inHighlightProcess() const;
|
||||||
void highlightProcessDone();
|
void highlightProcessDone();
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ public:
|
||||||
void applyChanges(not_null<Data::Story*> story);
|
void applyChanges(not_null<Data::Story*> story);
|
||||||
|
|
||||||
void applyEdition(const MTPDmessageService &message);
|
void applyEdition(const MTPDmessageService &message);
|
||||||
void applyEdition(const MTPMessageExtendedMedia &media);
|
void applyEdition(const QVector<MTPMessageExtendedMedia> &media);
|
||||||
void updateForwardedInfo(const MTPMessageFwdHeader *fwd);
|
void updateForwardedInfo(const MTPMessageFwdHeader *fwd);
|
||||||
void updateSentContent(
|
void updateSentContent(
|
||||||
const TextWithEntities &textWithEntities,
|
const TextWithEntities &textWithEntities,
|
||||||
|
|
|
@ -1091,8 +1091,8 @@ void HistoryMessageReplyMarkup::updateData(
|
||||||
bool HistoryMessageReplyMarkup::hiddenBy(Data::Media *media) const {
|
bool HistoryMessageReplyMarkup::hiddenBy(Data::Media *media) const {
|
||||||
if (media && (data.flags & ReplyMarkupFlag::OnlyBuyButton)) {
|
if (media && (data.flags & ReplyMarkupFlag::OnlyBuyButton)) {
|
||||||
if (const auto invoice = media->invoice()) {
|
if (const auto invoice = media->invoice()) {
|
||||||
if (invoice->extendedPreview
|
if (HasUnpaidMedia(*invoice)
|
||||||
&& (!invoice->extendedMedia || !invoice->receiptMsgId)) {
|
|| (HasExtendedMedia(*invoice) && !invoice->receiptMsgId)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -557,6 +557,8 @@ MediaCheckResult CheckMessageMedia(const MTPMessageMedia &media) {
|
||||||
return Result::Good;
|
return Result::Good;
|
||||||
}, [](const MTPDmessageMediaGiveawayResults &) {
|
}, [](const MTPDmessageMediaGiveawayResults &) {
|
||||||
return Result::Good;
|
return Result::Good;
|
||||||
|
}, [](const MTPDmessageMediaPaidMedia &) {
|
||||||
|
return Result::Good;
|
||||||
}, [](const MTPDmessageMediaUnsupported &) {
|
}, [](const MTPDmessageMediaUnsupported &) {
|
||||||
return Result::Unsupported;
|
return Result::Unsupported;
|
||||||
});
|
});
|
||||||
|
|
|
@ -2263,7 +2263,7 @@ void ListWidget::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session->data().reactions().poll(item, context.now);
|
session->data().reactions().poll(item, context.now);
|
||||||
if (item->hasExtendedMediaPreview()) {
|
if (item->hasUnpaidContent()) {
|
||||||
session->api().views().pollExtendedMedia(item);
|
session->api().views().pollExtendedMedia(item);
|
||||||
}
|
}
|
||||||
if (_reactionsManager) {
|
if (_reactionsManager) {
|
||||||
|
|
|
@ -1399,7 +1399,7 @@ CopyRestrictionType ScheduledWidget::listCopyMediaRestrictionType(
|
||||||
not_null<HistoryItem*> item) {
|
not_null<HistoryItem*> item) {
|
||||||
if (const auto media = item->media()) {
|
if (const auto media = item->media()) {
|
||||||
if (const auto invoice = media->invoice()) {
|
if (const auto invoice = media->invoice()) {
|
||||||
if (invoice->extendedMedia) {
|
if (HasExtendedMedia(*invoice)) {
|
||||||
return CopyMediaRestrictionTypeFor(_history->peer, item);
|
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),
|
: st::minPhotoSize),
|
||||||
thumbMaxWidth);
|
thumbMaxWidth);
|
||||||
const auto dimensions = photoSize();
|
const auto dimensions = photoSize();
|
||||||
auto pix = CountPhotoMediaSize(
|
auto pix = _data->extendedMediaVideoDuration()
|
||||||
CountDesiredMediaSize(dimensions),
|
? CountMediaSize(
|
||||||
newWidth,
|
CountDesiredMediaSize(dimensions),
|
||||||
maxWidth());
|
newWidth)
|
||||||
|
: CountPhotoMediaSize(
|
||||||
|
CountDesiredMediaSize(dimensions),
|
||||||
|
newWidth,
|
||||||
|
maxWidth());
|
||||||
newWidth = qMax(pix.width(), minWidth);
|
newWidth = qMax(pix.width(), minWidth);
|
||||||
auto newHeight = qMax(pix.height(), st::minPhotoSize);
|
auto newHeight = qMax(pix.height(), st::minPhotoSize);
|
||||||
if (_parent->hasBubble()) {
|
if (_parent->hasBubble()) {
|
||||||
|
|
|
@ -1362,7 +1362,7 @@ void OverlayWidget::updateControls() {
|
||||||
if (_message) {
|
if (_message) {
|
||||||
return ItemDateTime(_message);
|
return ItemDateTime(_message);
|
||||||
} else if (_photo) {
|
} else if (_photo) {
|
||||||
return base::unixtime::parse(_photo->date);
|
return base::unixtime::parse(_photo->date());
|
||||||
} else if (_document) {
|
} else if (_document) {
|
||||||
return base::unixtime::parse(_document->date);
|
return base::unixtime::parse(_document->date);
|
||||||
}
|
}
|
||||||
|
@ -2436,7 +2436,7 @@ void OverlayWidget::saveAs() {
|
||||||
u".mp4"_q,
|
u".mp4"_q,
|
||||||
QString(),
|
QString(),
|
||||||
false,
|
false,
|
||||||
_photo->date),
|
_photo->date()),
|
||||||
crl::guard(_window, [=](const QString &result) {
|
crl::guard(_window, [=](const QString &result) {
|
||||||
QFile f(result);
|
QFile f(result);
|
||||||
if (!result.isEmpty()
|
if (!result.isEmpty()
|
||||||
|
@ -2467,7 +2467,7 @@ void OverlayWidget::saveAs() {
|
||||||
u".jpg"_q,
|
u".jpg"_q,
|
||||||
QString(),
|
QString(),
|
||||||
false,
|
false,
|
||||||
_photo->date),
|
_photo->date()),
|
||||||
crl::guard(_window, [=](const QString &result) {
|
crl::guard(_window, [=](const QString &result) {
|
||||||
if (!result.isEmpty() && _photo == photo) {
|
if (!result.isEmpty() && _photo == photo) {
|
||||||
media->saveToFile(result);
|
media->saveToFile(result);
|
||||||
|
|
|
@ -44,6 +44,7 @@ inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> s
|
||||||
inputMediaDice#e66fbf7b emoticon:string = InputMedia;
|
inputMediaDice#e66fbf7b emoticon:string = InputMedia;
|
||||||
inputMediaStory#89fdd778 peer:InputPeer id:int = 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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
messageActionEmpty#b6aef7b0 = MessageAction;
|
||||||
messageActionChatCreate#bd47cbad title:string users:Vector<long> = 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;
|
updateRecentEmojiStatuses#30f443db = Update;
|
||||||
updateRecentReactions#6f7863f4 = Update;
|
updateRecentReactions#6f7863f4 = Update;
|
||||||
updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = 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;
|
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;
|
updateChannelPinnedTopics#fe198602 flags:# channel_id:long order:flags.0?Vector<int> = Update;
|
||||||
updateUser#20529438 user_id:long = 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;
|
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;
|
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;
|
fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;
|
||||||
|
|
||||||
// LAYER 182
|
// LAYER 183
|
||||||
|
|
|
@ -968,7 +968,7 @@ CopyRestrictionType ShortcutMessages::listCopyMediaRestrictionType(
|
||||||
not_null<HistoryItem*> item) {
|
not_null<HistoryItem*> item) {
|
||||||
if (const auto media = item->media()) {
|
if (const auto media = item->media()) {
|
||||||
if (const auto invoice = media->invoice()) {
|
if (const auto invoice = media->invoice()) {
|
||||||
if (invoice->extendedMedia) {
|
if (!invoice->extendedMedia.empty()) {
|
||||||
return CopyMediaRestrictionTypeFor(_history->peer, item);
|
return CopyMediaRestrictionTypeFor(_history->peer, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -416,7 +416,7 @@ void UserpicButton::openPeerPhoto() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto photo = _peer->owner().photo(id);
|
const auto photo = _peer->owner().photo(id);
|
||||||
if (photo->date && _controller) {
|
if (photo->date() && _controller) {
|
||||||
_controller->openPhoto(photo, _peer);
|
_controller->openPhoto(photo, _peer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -744,7 +744,7 @@ void UserpicButton::updateVideo() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto photo = _peer->owner().photo(id);
|
const auto photo = _peer->owner().photo(id);
|
||||||
if (!photo->date || !photo->videoCanBePlayed()) {
|
if (!photo->date() || !photo->videoCanBePlayed()) {
|
||||||
clearStreaming();
|
clearStreaming();
|
||||||
return;
|
return;
|
||||||
} else if (_streamed && _streamedPhoto == photo) {
|
} else if (_streamed && _streamedPhoto == photo) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue