Start customizable webpages.

This commit is contained in:
John Preston 2023-10-19 11:05:39 +04:00
parent 486d5b63d3
commit b2e8e0431e
16 changed files with 172 additions and 73 deletions

View file

@ -1434,9 +1434,11 @@ QString MediaCall::Text(
MediaWebPage::MediaWebPage( MediaWebPage::MediaWebPage(
not_null<HistoryItem*> parent, not_null<HistoryItem*> parent,
not_null<WebPageData*> page) not_null<WebPageData*> page,
MediaWebPageFlags flags)
: Media(parent) : Media(parent)
, _page(page) { , _page(page)
, _flags(flags) {
parent->history()->owner().registerWebPageItem(_page, parent); parent->history()->owner().registerWebPageItem(_page, parent);
} }
@ -1445,7 +1447,7 @@ MediaWebPage::~MediaWebPage() {
} }
std::unique_ptr<Media> MediaWebPage::clone(not_null<HistoryItem*> parent) { std::unique_ptr<Media> MediaWebPage::clone(not_null<HistoryItem*> parent) {
return std::make_unique<MediaWebPage>(parent, _page); return std::make_unique<MediaWebPage>(parent, _page, _flags);
} }
DocumentData *MediaWebPage::document() const { DocumentData *MediaWebPage::document() const {
@ -1524,7 +1526,7 @@ std::unique_ptr<HistoryView::Media> MediaWebPage::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) {
return std::make_unique<HistoryView::WebPage>(message, _page); return std::make_unique<HistoryView::WebPage>(message, _page, _flags);
} }
MediaGame::MediaGame( MediaGame::MediaGame(

View file

@ -372,7 +372,8 @@ class MediaWebPage final : public Media {
public: public:
MediaWebPage( MediaWebPage(
not_null<HistoryItem*> parent, not_null<HistoryItem*> parent,
not_null<WebPageData*> page); not_null<WebPageData*> page,
MediaWebPageFlags flags);
~MediaWebPage(); ~MediaWebPage();
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override; std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
@ -398,7 +399,8 @@ public:
HistoryView::Element *replacing = nullptr) override; HistoryView::Element *replacing = nullptr) override;
private: private:
not_null<WebPageData*> _page; const not_null<WebPageData*> _page;
const MediaWebPageFlags _flags;
}; };

View file

@ -3288,6 +3288,7 @@ not_null<WebPageData*> Session::processWebpage(const MTPDwebPagePending &data) {
webpageApplyFields( webpageApplyFields(
result, result,
WebPageType::Article, WebPageType::Article,
false,
QString(), QString(),
QString(), QString(),
QString(), QString(),
@ -3312,6 +3313,7 @@ not_null<WebPageData*> Session::webpage(
return webpage( return webpage(
id, id,
WebPageType::Article, WebPageType::Article,
false,
QString(), QString(),
QString(), QString(),
siteName, siteName,
@ -3328,6 +3330,7 @@ not_null<WebPageData*> Session::webpage(
not_null<WebPageData*> Session::webpage( not_null<WebPageData*> Session::webpage(
WebPageId id, WebPageId id,
WebPageType type, WebPageType type,
bool hasLargeMedia,
const QString &url, const QString &url,
const QString &displayUrl, const QString &displayUrl,
const QString &siteName, const QString &siteName,
@ -3343,6 +3346,7 @@ not_null<WebPageData*> Session::webpage(
webpageApplyFields( webpageApplyFields(
result, result,
type, type,
hasLargeMedia,
url, url,
displayUrl, displayUrl,
siteName, siteName,
@ -3434,6 +3438,7 @@ void Session::webpageApplyFields(
webpageApplyFields( webpageApplyFields(
page, page,
(story ? WebPageType::Story : ParseWebPageType(data)), (story ? WebPageType::Story : ParseWebPageType(data)),
data.is_has_large_media(),
qs(data.vurl()), qs(data.vurl()),
qs(data.vdisplay_url()), qs(data.vdisplay_url()),
siteName, siteName,
@ -3459,6 +3464,7 @@ void Session::webpageApplyFields(
void Session::webpageApplyFields( void Session::webpageApplyFields(
not_null<WebPageData*> page, not_null<WebPageData*> page,
WebPageType type, WebPageType type,
bool hasLargeMedia,
const QString &url, const QString &url,
const QString &displayUrl, const QString &displayUrl,
const QString &siteName, const QString &siteName,
@ -3474,6 +3480,7 @@ void Session::webpageApplyFields(
const auto requestPending = (!page->pendingTill && pendingTill > 0); const auto requestPending = (!page->pendingTill && pendingTill > 0);
const auto changed = page->applyChanges( const auto changed = page->applyChanges(
type, type,
hasLargeMedia,
url, url,
displayUrl, displayUrl,
siteName, siteName,

View file

@ -20,7 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class Image; class Image;
class HistoryItem; class HistoryItem;
struct WebPageCollage; struct WebPageCollage;
enum class WebPageType; enum class WebPageType : uint8;
enum class NewMessageType; enum class NewMessageType;
namespace HistoryView { namespace HistoryView {
@ -552,6 +552,7 @@ public:
[[nodiscard]] not_null<WebPageData*> webpage( [[nodiscard]] not_null<WebPageData*> webpage(
WebPageId id, WebPageId id,
WebPageType type, WebPageType type,
bool hasLargeMedia,
const QString &url, const QString &url,
const QString &displayUrl, const QString &displayUrl,
const QString &siteName, const QString &siteName,
@ -813,6 +814,7 @@ private:
void webpageApplyFields( void webpageApplyFields(
not_null<WebPageData*> page, not_null<WebPageData*> page,
WebPageType type, WebPageType type,
bool hasLargeMedia,
const QString &url, const QString &url,
const QString &displayUrl, const QString &displayUrl,
const QString &siteName, const QString &siteName,

View file

@ -246,65 +246,75 @@ enum class MessageFlag : uint64 {
MentionsMe = (1ULL << 15), MentionsMe = (1ULL << 15),
IsOrWasScheduled = (1ULL << 16), IsOrWasScheduled = (1ULL << 16),
NoForwards = (1ULL << 17), NoForwards = (1ULL << 17),
InvertMedia = (1ULL << 18),
// Needs to return back to inline mode. // Needs to return back to inline mode.
HasSwitchInlineButton = (1ULL << 18), HasSwitchInlineButton = (1ULL << 19),
// For "shared links" indexing. // For "shared links" indexing.
HasTextLinks = (1ULL << 19), HasTextLinks = (1ULL << 20),
// Group / channel create or migrate service message. // Group / channel create or migrate service message.
IsGroupEssential = (1ULL << 20), IsGroupEssential = (1ULL << 21),
// Edited media is generated on the client // Edited media is generated on the client
// and should not update media from server. // and should not update media from server.
IsLocalUpdateMedia = (1ULL << 21), IsLocalUpdateMedia = (1ULL << 22),
// Sent from inline bot, need to re-set media when sent. // Sent from inline bot, need to re-set media when sent.
FromInlineBot = (1ULL << 22), FromInlineBot = (1ULL << 23),
// Generated on the client side and should be unread. // Generated on the client side and should be unread.
ClientSideUnread = (1ULL << 23), ClientSideUnread = (1ULL << 24),
// In a supergroup. // In a supergroup.
HasAdminBadge = (1ULL << 24), HasAdminBadge = (1ULL << 25),
// Outgoing message that is being sent. // Outgoing message that is being sent.
BeingSent = (1ULL << 25), BeingSent = (1ULL << 26),
// Outgoing message and failed to be sent. // Outgoing message and failed to be sent.
SendingFailed = (1ULL << 26), SendingFailed = (1ULL << 27),
// No media and only a several emoji or an only custom emoji text. // No media and only a several emoji or an only custom emoji text.
SpecialOnlyEmoji = (1ULL << 27), SpecialOnlyEmoji = (1ULL << 28),
// Message existing in the message history. // Message existing in the message history.
HistoryEntry = (1ULL << 28), HistoryEntry = (1ULL << 29),
// Local message, not existing on the server. // Local message, not existing on the server.
Local = (1ULL << 29), Local = (1ULL << 30),
// Fake message for some UI element. // Fake message for some UI element.
FakeHistoryItem = (1ULL << 30), FakeHistoryItem = (1ULL << 31),
// Contact sign-up message, notification should be skipped for Silent. // Contact sign-up message, notification should be skipped for Silent.
IsContactSignUp = (1ULL << 31), IsContactSignUp = (1ULL << 32),
// Optimization for item text custom emoji repainting. // Optimization for item text custom emoji repainting.
CustomEmojiRepainting = (1ULL << 32), CustomEmojiRepainting = (1ULL << 33),
// Profile photo suggestion, views have special media type. // Profile photo suggestion, views have special media type.
IsUserpicSuggestion = (1ULL << 33), IsUserpicSuggestion = (1ULL << 34),
OnlyEmojiAndSpaces = (1ULL << 34), OnlyEmojiAndSpaces = (1ULL << 35),
OnlyEmojiAndSpacesSet = (1ULL << 35), OnlyEmojiAndSpacesSet = (1ULL << 36),
// Fake message with bot cover and information. // Fake message with bot cover and information.
FakeBotAbout = (1ULL << 36), FakeBotAbout = (1ULL << 37),
StoryItem = (1ULL << 37), StoryItem = (1ULL << 38),
InHighlightProcess = (1ULL << 38), InHighlightProcess = (1ULL << 39),
}; };
inline constexpr bool is_flag_type(MessageFlag) { return true; } inline constexpr bool is_flag_type(MessageFlag) { return true; }
using MessageFlags = base::flags<MessageFlag>; using MessageFlags = base::flags<MessageFlag>;
enum class MediaWebPageFlag : uint8 {
ForceLargeMedia = (1 << 0),
ForceSmallMedia = (1 << 1),
Manual = (1 << 2),
Safe = (1 << 3),
};
inline constexpr bool is_flag_type(MediaWebPageFlag) { return true; }
using MediaWebPageFlags = base::flags<MediaWebPageFlag>;

View file

@ -213,6 +213,7 @@ Main::Session &WebPageData::session() const {
bool WebPageData::applyChanges( bool WebPageData::applyChanges(
WebPageType newType, WebPageType newType,
bool newHasLargeMedia,
const QString &newUrl, const QString &newUrl,
const QString &newDisplayUrl, const QString &newDisplayUrl,
const QString &newSiteName, const QString &newSiteName,
@ -254,6 +255,7 @@ bool WebPageData::applyChanges(
}(); }();
if (type == newType if (type == newType
&& hasLargeMedia == newHasLargeMedia
&& url == resultUrl && url == resultUrl
&& displayUrl == resultDisplayUrl && displayUrl == resultDisplayUrl
&& siteName == resultSiteName && siteName == resultSiteName
@ -272,6 +274,7 @@ bool WebPageData::applyChanges(
_owner->session().api().clearWebPageRequest(this); _owner->session().api().clearWebPageRequest(this);
} }
type = newType; type = newType;
hasLargeMedia = newHasLargeMedia;
url = resultUrl; url = resultUrl;
displayUrl = resultDisplayUrl; displayUrl = resultDisplayUrl;
siteName = resultSiteName; siteName = resultSiteName;

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/flags.h"
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_document.h" #include "data/data_document.h"
@ -16,7 +17,7 @@ namespace Data {
class Session; class Session;
} // namespace Data } // namespace Data
enum class WebPageType { enum class WebPageType : uint8 {
Message, Message,
Group, Group,
@ -44,8 +45,7 @@ enum class WebPageType {
VoiceChat, VoiceChat,
Livestream, Livestream,
}; };
[[nodiscard]] WebPageType ParseWebPageType(const MTPDwebPage &type);
WebPageType ParseWebPageType(const MTPDwebPage &type);
struct WebPageCollage { struct WebPageCollage {
using Item = std::variant<PhotoData*, DocumentData*>; using Item = std::variant<PhotoData*, DocumentData*>;
@ -67,6 +67,7 @@ struct WebPageData {
bool applyChanges( bool applyChanges(
WebPageType newType, WebPageType newType,
bool newHasLargeMedia,
const QString &newUrl, const QString &newUrl,
const QString &newDisplayUrl, const QString &newDisplayUrl,
const QString &newSiteName, const QString &newSiteName,
@ -87,17 +88,18 @@ struct WebPageData {
WebPageId id = 0; WebPageId id = 0;
WebPageType type = WebPageType::Article; WebPageType type = WebPageType::Article;
bool hasLargeMedia = false;
QString url; QString url;
QString displayUrl; QString displayUrl;
QString siteName; QString siteName;
QString title; QString title;
TextWithEntities description; TextWithEntities description;
FullStoryId storyId; FullStoryId storyId;
int duration = 0;
QString author; QString author;
PhotoData *photo = nullptr; PhotoData *photo = nullptr;
DocumentData *document = nullptr; DocumentData *document = nullptr;
WebPageCollage collage; WebPageCollage collage;
int duration = 0;
int pendingTill = 0; int pendingTill = 0;
int version = 0; int version = 0;

View file

@ -252,16 +252,28 @@ std::unique_ptr<Data::Media> HistoryItem::CreateMedia(
return nullptr; return nullptr;
}); });
}, [&](const MTPDmessageMediaWebPage &media) { }, [&](const MTPDmessageMediaWebPage &media) {
using Flag = MediaWebPageFlag;
const auto flags = Flag()
| (media.is_force_large_media()
? Flag::ForceLargeMedia
: Flag())
| (media.is_force_small_media()
? Flag::ForceSmallMedia
: Flag())
| (media.is_manual() ? Flag::Manual : Flag())
| (media.is_safe() ? Flag::Safe : Flag());
return media.vwebpage().match([](const MTPDwebPageEmpty &) -> Result { return media.vwebpage().match([](const MTPDwebPageEmpty &) -> Result {
return nullptr; return nullptr;
}, [&](const MTPDwebPagePending &webpage) -> Result { }, [&](const MTPDwebPagePending &webpage) -> Result {
return std::make_unique<Data::MediaWebPage>( return std::make_unique<Data::MediaWebPage>(
item, item,
item->history()->owner().processWebpage(webpage)); item->history()->owner().processWebpage(webpage),
flags);
}, [&](const MTPDwebPage &webpage) -> Result { }, [&](const MTPDwebPage &webpage) -> Result {
return std::make_unique<Data::MediaWebPage>( return std::make_unique<Data::MediaWebPage>(
item, item,
item->history()->owner().processWebpage(webpage)); item->history()->owner().processWebpage(webpage),
flags);
}, [](const MTPDwebPageNotModified &) -> Result { }, [](const MTPDwebPageNotModified &) -> Result {
LOG(("API Error: " LOG(("API Error: "
"webPageNotModified is unexpected in message media.")); "webPageNotModified is unexpected in message media."));
@ -503,6 +515,9 @@ HistoryItem::HistoryItem(
}; };
if (mediaOriginal && !ignoreMedia()) { if (mediaOriginal && !ignoreMedia()) {
_media = mediaOriginal->clone(this); _media = mediaOriginal->clone(this);
if (original->invertMedia()) {
_flags |= MessageFlag::InvertMedia;
}
} }
const auto dropCustomEmoji = dropForwardInfo const auto dropCustomEmoji = dropForwardInfo

View file

@ -240,6 +240,9 @@ public:
[[nodiscard]] bool isPinned() const { [[nodiscard]] bool isPinned() const {
return _flags & MessageFlag::Pinned; return _flags & MessageFlag::Pinned;
} }
[[nodiscard]] bool invertMedia() const {
return _flags & MessageFlag::InvertMedia;
}
[[nodiscard]] bool unread(not_null<Data::Thread*> thread) const; [[nodiscard]] bool unread(not_null<Data::Thread*> thread) const;
[[nodiscard]] bool showNotification() const; [[nodiscard]] bool showNotification() const;
void markClientSideAsRead(); void markClientSideAsRead();

View file

@ -331,9 +331,12 @@ MessageFlags FlagsFromMTP(
| ((flags & MTP::f_from_id) ? Flag::HasFromId : Flag()) | ((flags & MTP::f_from_id) ? Flag::HasFromId : Flag())
| ((flags & MTP::f_reply_to) ? Flag::HasReplyInfo : Flag()) | ((flags & MTP::f_reply_to) ? Flag::HasReplyInfo : Flag())
| ((flags & MTP::f_reply_markup) ? Flag::HasReplyMarkup : Flag()) | ((flags & MTP::f_reply_markup) ? Flag::HasReplyMarkup : Flag())
| ((flags & MTP::f_from_scheduled) ? Flag::IsOrWasScheduled : Flag()) | ((flags & MTP::f_from_scheduled)
? Flag::IsOrWasScheduled
: Flag())
| ((flags & MTP::f_views) ? Flag::HasViews : Flag()) | ((flags & MTP::f_views) ? Flag::HasViews : Flag())
| ((flags & MTP::f_noforwards) ? Flag::NoForwards : Flag()); | ((flags & MTP::f_noforwards) ? Flag::NoForwards : Flag())
| ((flags & MTP::f_invert_media) ? Flag::InvertMedia : Flag());
} }
MessageFlags FlagsFromMTP( MessageFlags FlagsFromMTP(

View file

@ -411,6 +411,7 @@ Message::Message(
not_null<HistoryItem*> data, not_null<HistoryItem*> data,
Element *replacing) Element *replacing)
: Element(delegate, data, replacing, Flag(0)) : Element(delegate, data, replacing, Flag(0))
, _invertMedia(data->invertMedia() && !data->emptyText())
, _bottomInfo( , _bottomInfo(
&data->history()->owner().reactions(), &data->history()->owner().reactions(),
BottomInfoDataFromMessage(this)) { BottomInfoDataFromMessage(this)) {
@ -1078,16 +1079,20 @@ void Message::draw(Painter &p, const PaintContext &context) const {
trect.setHeight(trect.height() trect.setHeight(trect.height()
- (_bottomInfo.height() - st::msgDateFont->height)); - (_bottomInfo.height() - st::msgDateFont->height));
} }
paintText(p, trect, context); auto textSelection = context.selection;
if (mediaDisplayed) { const auto mediaHeight = mediaDisplayed ? media->height() : 0;
auto mediaHeight = media->height(); const auto paintMedia = [&](int top) {
auto mediaPosition = QPoint( if (!mediaDisplayed) {
inner.left(), return;
trect.y() + trect.height() - mediaHeight); }
const auto mediaSelection = _invertMedia
? context.selection
: skipTextSelection(context.selection);
auto mediaPosition = QPoint(inner.left(), top);
p.translate(mediaPosition); p.translate(mediaPosition);
media->draw(p, context.translated( media->draw(p, context.translated(
-mediaPosition -mediaPosition
).withSelection(skipTextSelection(context.selection))); ).withSelection(mediaSelection));
if (context.reactionInfo && !displayInfo && !_reactions) { if (context.reactionInfo && !displayInfo && !_reactions) {
const auto add = QPoint(0, mediaHeight); const auto add = QPoint(0, mediaHeight);
context.reactionInfo->position = mediaPosition + add; context.reactionInfo->position = mediaPosition + add;
@ -1096,6 +1101,27 @@ void Message::draw(Painter &p, const PaintContext &context) const {
} }
} }
p.translate(-mediaPosition); p.translate(-mediaPosition);
};
if (mediaDisplayed && _invertMedia) {
if (!mediaOnTop) {
trect.setY(trect.y() + st::mediaInBubbleSkip);
}
paintMedia(trect.y());
trect.setY(trect.y()
+ mediaHeight
+ (mediaOnBottom ? 0 : st::mediaInBubbleSkip));
textSelection = media->skipSelection(textSelection);
}
paintText(p, trect, context.withSelection(textSelection));
if (mediaDisplayed && !_invertMedia) {
paintMedia(trect.y() + trect.height() - mediaHeight);
if (context.reactionInfo && !displayInfo && !_reactions) {
context.reactionInfo->position
= QPoint(inner.left(), trect.y() + trect.height());
if (context.reactionInfo->effectPaint) {
context.reactionInfo->effectOffset -= QPoint(0, mediaHeight);
}
}
} }
if (entry) { if (entry) {
auto entryLeft = inner.left(); auto entryLeft = inner.left();
@ -2106,25 +2132,33 @@ TextState Message::textState(
} }
}; };
if (!result.symbol && inBubble) { if (!result.symbol && inBubble) {
if (mediaDisplayed) { const auto mediaHeight = mediaDisplayed ? media->height() : 0;
auto mediaHeight = media->height(); const auto mediaLeft = trect.x() - st::msgPadding.left();
auto mediaLeft = trect.x() - st::msgPadding.left(); const auto mediaTop = (!mediaDisplayed || _invertMedia)
auto mediaTop = (trect.y() + trect.height() - mediaHeight); ? (trect.y() + (mediaOnTop ? 0 : st::mediaInBubbleSkip))
: (trect.y() + trect.height() - mediaHeight);
if (point.y() >= mediaTop && point.y() < mediaTop + mediaHeight) { if (mediaDisplayed && _invertMedia) {
result = media->textState(point - QPoint(mediaLeft, mediaTop), request); trect.setY(mediaTop
+ mediaHeight
+ (mediaOnBottom ? 0 : st::mediaInBubbleSkip));
}
if (point.y() >= mediaTop
&& point.y() < mediaTop + mediaHeight) {
result = media->textState(
point - QPoint(mediaLeft, mediaTop),
request);
if (!_invertMedia) {
result.symbol += visibleTextLength(); result.symbol += visibleTextLength();
} else if (getStateText(point, trect, &result, request)) {
checkBottomInfoState();
return result;
} else if (point.y() >= trect.y() + trect.height()) {
result.symbol = visibleTextLength();
} }
} else if (getStateText(point, trect, &result, request)) { } else if (getStateText(point, trect, &result, request)) {
if (_invertMedia) {
result.symbol += visibleMediaTextLength();
}
checkBottomInfoState(); checkBottomInfoState();
return result; return result;
} else if (point.y() >= trect.y() + trect.height()) { } else if (point.y() >= trect.y() + trect.height()) {
result.symbol = visibleTextLength(); result.symbol = visibleTextLength()
+ visibleMediaTextLength();
} }
} }
checkBottomInfoState(); checkBottomInfoState();
@ -3031,7 +3065,8 @@ void Message::initLogEntryOriginal() {
if (const auto log = data()->Get<HistoryMessageLogEntryOriginal>()) { if (const auto log = data()->Get<HistoryMessageLogEntryOriginal>()) {
AddComponents(LogEntryOriginal::Bit()); AddComponents(LogEntryOriginal::Bit());
const auto entry = Get<LogEntryOriginal>(); const auto entry = Get<LogEntryOriginal>();
entry->page = std::make_unique<WebPage>(this, log->page); using Flags = MediaWebPageFlags;
entry->page = std::make_unique<WebPage>(this, log->page, Flags());
} }
} }
@ -3491,7 +3526,8 @@ void Message::updateMediaInBubbleState() {
} }
const auto reactionsInBubble = (_reactions && embedReactionsInBubble()); const auto reactionsInBubble = (_reactions && embedReactionsInBubble());
auto mediaHasSomethingBelow = (_viewButton != nullptr) auto mediaHasSomethingBelow = (_viewButton != nullptr)
|| reactionsInBubble; || reactionsInBubble
|| (invertMedia() && hasVisibleText());
auto mediaHasSomethingAbove = false; auto mediaHasSomethingAbove = false;
auto getMediaHasSomethingAbove = [&] { auto getMediaHasSomethingAbove = [&] {
return displayFromName() return displayFromName()
@ -3529,7 +3565,7 @@ void Message::updateMediaInBubbleState() {
if (!entry) { if (!entry) {
mediaHasSomethingAbove = getMediaHasSomethingAbove(); mediaHasSomethingAbove = getMediaHasSomethingAbove();
} }
if (hasVisibleText()) { if (!invertMedia() && hasVisibleText()) {
mediaHasSomethingAbove = true; mediaHasSomethingAbove = true;
} }
const auto state = [&] { const auto state = [&] {
@ -3661,7 +3697,7 @@ QRect Message::countGeometry() const {
// contentLeft += st::msgPhotoSkip - (hmaxwidth - hwidth); // contentLeft += st::msgPhotoSkip - (hmaxwidth - hwidth);
} }
accumulate_min(contentWidth, maxWidth()); accumulate_min(contentWidth, maxWidth());
accumulate_min(contentWidth, _bubbleWidthLimit); accumulate_min(contentWidth, int(_bubbleWidthLimit));
if (mediaWidth < contentWidth) { if (mediaWidth < contentWidth) {
const auto textualWidth = plainMaxWidth(); const auto textualWidth = plainMaxWidth();
if (mediaWidth < textualWidth if (mediaWidth < textualWidth
@ -3768,7 +3804,7 @@ int Message::resizeContentGetHeight(int newWidth) {
} }
accumulate_min(contentWidth, maxWidth()); accumulate_min(contentWidth, maxWidth());
_bubbleWidthLimit = std::max(st::msgMaxWidth, monospaceMaxWidth()); _bubbleWidthLimit = std::max(st::msgMaxWidth, monospaceMaxWidth());
accumulate_min(contentWidth, _bubbleWidthLimit); accumulate_min(contentWidth, int(_bubbleWidthLimit));
if (mediaDisplayed) { if (mediaDisplayed) {
media->resizeGetHeight(contentWidth); media->resizeGetHeight(contentWidth);
if (media->width() < contentWidth) { if (media->width() < contentWidth) {
@ -3924,11 +3960,15 @@ bool Message::needInfoDisplay() const {
const auto entry = logEntryOriginal(); const auto entry = logEntryOriginal();
return entry return entry
? !entry->customInfoLayout() ? !entry->customInfoLayout()
: (mediaDisplayed : ((mediaDisplayed && media->isBubbleBottom())
? !media->customInfoLayout() ? !media->customInfoLayout()
: true); : true);
} }
bool Message::invertMedia() const {
return _invertMedia;
}
bool Message::hasVisibleText() const { bool Message::hasVisibleText() const {
if (data()->emptyText()) { if (data()->emptyText()) {
if (const auto media = data()->media()) { if (const auto media = data()->media()) {

View file

@ -270,6 +270,7 @@ private:
[[nodiscard]] int visibleTextLength() const; [[nodiscard]] int visibleTextLength() const;
[[nodiscard]] int visibleMediaTextLength() const; [[nodiscard]] int visibleMediaTextLength() const;
[[nodiscard]] bool needInfoDisplay() const; [[nodiscard]] bool needInfoDisplay() const;
[[nodiscard]] bool invertMedia() const;
[[nodiscard]] bool isPinnedContext() const; [[nodiscard]] bool isPinnedContext() const;
@ -309,7 +310,8 @@ private:
mutable std::unique_ptr<FromNameStatus> _fromNameStatus; mutable std::unique_ptr<FromNameStatus> _fromNameStatus;
Ui::Text::String _rightBadge; Ui::Text::String _rightBadge;
mutable int _fromNameVersion = 0; mutable int _fromNameVersion = 0;
int _bubbleWidthLimit = 0; uint32 _bubbleWidthLimit : 31 = 0;
uint32 _invertMedia : 1 = 0;
BottomInfo _bottomInfo; BottomInfo _bottomInfo;

View file

@ -121,14 +121,16 @@ std::vector<std::unique_ptr<Data::Media>> PrepareCollageMedia(
WebPage::WebPage( WebPage::WebPage(
not_null<Element*> parent, not_null<Element*> parent,
not_null<WebPageData*> data) not_null<WebPageData*> data,
MediaWebPageFlags flags)
: Media(parent) : Media(parent)
, _st(st::historyPagePreview) , _st(st::historyPagePreview)
, _data(data) , _data(data)
, _colorIndex(parent->data()->computeColorIndex()) , _colorIndex(parent->data()->computeColorIndex())
, _siteName(st::msgMinWidth - _st.padding.left() - _st.padding.right()) , _siteName(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _title(st::msgMinWidth - _st.padding.left() - _st.padding.right()) , _title(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _description(st::msgMinWidth - _st.padding.left() - _st.padding.right()) { , _description(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _flags(flags) {
history()->owner().registerWebPageView(_data, _parent); history()->owner().registerWebPageView(_data, _parent);
} }
@ -238,7 +240,12 @@ QSize WebPage::countOptimalSize() {
auto title = TextUtilities::SingleLine(_data->title.isEmpty() auto title = TextUtilities::SingleLine(_data->title.isEmpty()
? _data->author ? _data->author
: _data->title); : _data->title);
if (!_collage.empty()) { using Flag = MediaWebPageFlag;
if (_data->hasLargeMedia && (_flags & Flag::ForceLargeMedia)) {
_asArticle = 0;
} else if (_data->photo && (_flags & Flag::ForceSmallMedia)) {
_asArticle = 1;
} else if (!_collage.empty()) {
_asArticle = 0; _asArticle = 0;
} else if (!_data->document } else if (!_data->document
&& _data->photo && _data->photo
@ -956,11 +963,9 @@ TextForMimeData WebPage::selectedText(TextSelection selection) const {
QMargins WebPage::inBubblePadding() const { QMargins WebPage::inBubblePadding() const {
return { return {
st::msgPadding.left(), st::msgPadding.left(),
isBubbleTop() ? st::msgPadding.left() : st::mediaInBubbleSkip, isBubbleTop() ? st::msgPadding.left() : 0,
st::msgPadding.right(), st::msgPadding.right(),
(isBubbleBottom() isBubbleBottom() ? (st::msgPadding.left() + bottomInfoPadding()) : 0
? (st::msgPadding.left() + bottomInfoPadding())
: st::mediaInBubbleSkip),
}; };
} }

View file

@ -24,7 +24,8 @@ class WebPage : public Media {
public: public:
WebPage( WebPage(
not_null<Element*> parent, not_null<Element*> parent,
not_null<WebPageData*> data); not_null<WebPageData*> data,
MediaWebPageFlags flags);
[[nodiscard]] static bool HasButton(not_null<WebPageData*> data); [[nodiscard]] static bool HasButton(not_null<WebPageData*> data);
@ -151,6 +152,8 @@ private:
int _pixw = 0; int _pixw = 0;
int _pixh = 0; int _pixh = 0;
const MediaWebPageFlags _flags;
}; };
} // namespace HistoryView } // namespace HistoryView

View file

@ -2168,5 +2168,5 @@ stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool;
premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList;
premium.getMyBoosts#be77b4a = premium.MyBoosts; premium.getMyBoosts#be77b4a = premium.MyBoosts;
premium.applyBoost#46b6a16b flags:# slot:flags.0?int peer:InputPeer = Bool; premium.applyBoost#184bc3b9 flags:# slots:flags.0?Vector<int> peer:InputPeer = Bool;
premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus;

View file

@ -785,7 +785,7 @@ void SessionNavigation::applyBoostChecked(
Fn<void(bool)> done) { Fn<void(bool)> done) {
_api.request(MTPpremium_ApplyBoost( _api.request(MTPpremium_ApplyBoost(
MTP_flags(0), MTP_flags(0),
MTPint(), // slot MTPVector<MTPint>(), // slots
channel->input channel->input
)).done([=](const MTPBool &result) { )).done([=](const MTPBool &result) {
done(true); done(true);