Added view button to webpages.
This commit is contained in:
parent
1613495425
commit
6163e922b3
|
@ -2893,6 +2893,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_view_button_bot" = "View bot";
|
||||
"lng_view_button_group" = "View group";
|
||||
"lng_view_button_channel" = "View channel";
|
||||
"lng_view_button_background" = "View background";
|
||||
"lng_view_button_theme" = "View theme";
|
||||
"lng_view_button_message" = "View message";
|
||||
"lng_view_button_voice_chat" = "Voice chat";
|
||||
"lng_view_button_voice_chat_channel" = "Live stream";
|
||||
|
||||
"lng_sponsored_title" = "What are sponsored messages?";
|
||||
"lng_sponsored_info_description1" = "Unlike other apps, Telegram never uses your private data to target ads. Sponsored messages on Telegram are based solely on the topic of the public channels in which they are shown. This means that no user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored messages.\n\nUnlike other apps, Telegram doesn't track whether you tapped on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties can’t spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that.\n\nTelegram offers a free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible advertisers at:";
|
||||
|
|
|
@ -146,6 +146,20 @@ WebPageType ParseWebPageType(const MTPDwebPage &page) {
|
|||
return WebPageType::WallPaper;
|
||||
} else if (type == qstr("telegram_theme")) {
|
||||
return WebPageType::Theme;
|
||||
} else if (type == qstr("telegram_channel")) {
|
||||
return WebPageType::Channel;
|
||||
} else if (type == qstr("telegram_message")) {
|
||||
return WebPageType::Message;
|
||||
} else if (type == qstr("telegram_bot")) {
|
||||
return WebPageType::Bot;
|
||||
} else if (type == qstr("telegram_megagroup")) {
|
||||
return WebPageType::Group;
|
||||
} else if (type == qstr("telegram_voicechat")) {
|
||||
return WebPageType::VoiceChat;
|
||||
} else if (type == qstr("telegram_livestream")) {
|
||||
return WebPageType::Livestream;
|
||||
} else if (type == qstr("telegram_user")) {
|
||||
return WebPageType::User;
|
||||
} else if (page.vcached_page()) {
|
||||
return WebPageType::ArticleWithIV;
|
||||
} else {
|
||||
|
@ -302,4 +316,4 @@ void WebPageData::ApplyChanges(
|
|||
});
|
||||
}
|
||||
session->data().sendWebPageGamePollNotifications();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,26 @@ class Session;
|
|||
} // namespace Data
|
||||
|
||||
enum class WebPageType {
|
||||
Message,
|
||||
|
||||
Group,
|
||||
Channel,
|
||||
|
||||
Photo,
|
||||
Video,
|
||||
|
||||
User,
|
||||
Bot,
|
||||
Profile,
|
||||
|
||||
WallPaper,
|
||||
Theme,
|
||||
|
||||
Article,
|
||||
ArticleWithIV,
|
||||
|
||||
VoiceChat,
|
||||
Livestream,
|
||||
};
|
||||
|
||||
WebPageType ParseWebPageType(const MTPDwebPage &type);
|
||||
|
|
|
@ -243,12 +243,6 @@ Message::Message(
|
|||
: Element(delegate, data, replacing) {
|
||||
initLogEntryOriginal();
|
||||
initPsa();
|
||||
|
||||
if (data->isSponsored()) {
|
||||
_viewButton = std::make_unique<ViewButton>(
|
||||
data->displayFrom(),
|
||||
[=] { history()->owner().requestViewRepaint(this); });
|
||||
}
|
||||
}
|
||||
|
||||
Message::~Message() {
|
||||
|
@ -611,16 +605,18 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
|||
|
||||
auto inner = g;
|
||||
paintCommentsButton(p, inner, context);
|
||||
if (_viewButton) {
|
||||
if (ensureViewButton()) {
|
||||
_viewButton->draw(
|
||||
p,
|
||||
_viewButton->countSponsoredRect(inner),
|
||||
_viewButton->countRect(inner),
|
||||
context);
|
||||
}
|
||||
|
||||
auto trect = inner.marginsRemoved(st::msgPadding);
|
||||
if (mediaOnBottom) {
|
||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||
trect.setHeight(trect.height()
|
||||
+ st::msgPadding.bottom()
|
||||
- viewButtonHeight());
|
||||
}
|
||||
if (mediaOnTop) {
|
||||
trect.setY(trect.y() - st::msgPadding.top());
|
||||
|
@ -1208,14 +1204,16 @@ TextState Message::textState(
|
|||
if (_viewButton
|
||||
&& _viewButton->getState(
|
||||
point,
|
||||
_viewButton->countSponsoredRect(bubble),
|
||||
_viewButton->countRect(bubble),
|
||||
&result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto trect = bubble.marginsRemoved(st::msgPadding);
|
||||
if (mediaOnBottom) {
|
||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||
trect.setHeight(trect.height()
|
||||
+ st::msgPadding.bottom()
|
||||
- viewButtonHeight());
|
||||
}
|
||||
if (mediaOnTop) {
|
||||
trect.setY(trect.y() - st::msgPadding.top());
|
||||
|
@ -1754,7 +1752,7 @@ void Message::drawInfo(
|
|||
; msgsigned && !msgsigned->isAnonymousRank) {
|
||||
msgsigned->signature.drawElided(p, dateX, dateY, item->_timeWidth);
|
||||
} else if (const auto sponsored = displayedSponsorBadge()) {
|
||||
const auto skipY = _viewButton ? _viewButton->height() : 0;
|
||||
const auto skipY = viewButtonHeight();
|
||||
sponsored->text.drawElided(p, dateX, dateY - skipY, item->_timeWidth);
|
||||
} else if (const auto edited = displayedEditBadge()) {
|
||||
edited->text.drawElided(p, dateX, dateY, item->_timeWidth);
|
||||
|
@ -1958,6 +1956,33 @@ int Message::monospaceMaxWidth() const {
|
|||
+ st::msgPadding.right();
|
||||
}
|
||||
|
||||
int Message::viewButtonHeight() const {
|
||||
return _viewButton ? _viewButton->height() : 0;
|
||||
}
|
||||
|
||||
bool Message::ensureViewButton() const {
|
||||
if (data()->isSponsored()
|
||||
|| (data()->media()
|
||||
&& ViewButton::MediaHasViewButton(data()->media()))) {
|
||||
if (_viewButton) {
|
||||
return true;
|
||||
}
|
||||
auto callback = [=] { history()->owner().requestViewRepaint(this); };
|
||||
_viewButton = data()->isSponsored()
|
||||
? std::make_unique<ViewButton>(
|
||||
data()->displayFrom(),
|
||||
std::move(callback))
|
||||
: std::make_unique<ViewButton>(
|
||||
data()->media(),
|
||||
std::move(callback));
|
||||
return true;
|
||||
}
|
||||
if (_viewButton) {
|
||||
_viewButton.reset(nullptr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Message::initLogEntryOriginal() {
|
||||
if (const auto log = message()->Get<HistoryMessageLogEntryOriginal>()) {
|
||||
AddComponents(LogEntryOriginal::Bit());
|
||||
|
@ -2618,8 +2643,8 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
if (item->repliesAreComments() || item->externalReply()) {
|
||||
newHeight += st::historyCommentsButtonHeight;
|
||||
}
|
||||
if (_viewButton) {
|
||||
newHeight += _viewButton->height();
|
||||
if (ensureViewButton()) {
|
||||
newHeight += viewButtonHeight();
|
||||
}
|
||||
} else if (mediaDisplayed) {
|
||||
newHeight = media->height();
|
||||
|
|
|
@ -213,6 +213,9 @@ private:
|
|||
[[nodiscard]] int plainMaxWidth() const;
|
||||
[[nodiscard]] int monospaceMaxWidth() const;
|
||||
|
||||
[[nodiscard]] bool ensureViewButton() const;
|
||||
[[nodiscard]] int viewButtonHeight() const;
|
||||
|
||||
WebPage *logEntryOriginal() const;
|
||||
|
||||
[[nodiscard]] ClickHandlerPtr createGoToCommentsLink() const;
|
||||
|
@ -224,7 +227,7 @@ private:
|
|||
mutable ClickHandlerPtr _rightActionLink;
|
||||
mutable ClickHandlerPtr _fastReplyLink;
|
||||
mutable std::unique_ptr<CommentsButton> _comments;
|
||||
std::unique_ptr<ViewButton> _viewButton;
|
||||
mutable std::unique_ptr<ViewButton> _viewButton;
|
||||
|
||||
Ui::Text::String _rightBadge;
|
||||
int _bubbleWidthLimit = 0;
|
||||
|
|
|
@ -7,10 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "history/view/history_view_view_button.h"
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "data/data_cloud_themes.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_sponsored_messages.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "history/view/history_view_cursor_state.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -42,22 +45,71 @@ inline auto PeerToPhrase(not_null<PeerData*> peer) {
|
|||
return Ui::Text::Upper(phrase);
|
||||
}
|
||||
|
||||
inline auto WebPageToPhrase(not_null<WebPageData*> webpage) {
|
||||
const auto type = webpage->type;
|
||||
return Ui::Text::Upper((type == WebPageType::Theme)
|
||||
? tr::lng_view_button_theme(tr::now)
|
||||
: (type == WebPageType::Message)
|
||||
? tr::lng_view_button_message(tr::now)
|
||||
: (type == WebPageType::Group)
|
||||
? tr::lng_view_button_group(tr::now)
|
||||
: (type == WebPageType::WallPaper)
|
||||
? tr::lng_view_button_background(tr::now)
|
||||
: (type == WebPageType::Channel)
|
||||
? tr::lng_view_button_channel(tr::now)
|
||||
: (type == WebPageType::VoiceChat)
|
||||
? tr::lng_view_button_voice_chat(tr::now)
|
||||
: (type == WebPageType::Livestream)
|
||||
? tr::lng_view_button_voice_chat_channel(tr::now)
|
||||
: (type == WebPageType::Bot)
|
||||
? tr::lng_view_button_bot(tr::now)
|
||||
: (type == WebPageType::User)
|
||||
? tr::lng_view_button_user(tr::now)
|
||||
: QString());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct ViewButton::Inner {
|
||||
Inner(not_null<PeerData*> peer, Fn<void()> updateCallback);
|
||||
Inner(not_null<Data::Media*> media, Fn<void()> updateCallback);
|
||||
void updateMask(int height);
|
||||
void toggleRipple(bool pressed);
|
||||
|
||||
const style::margins &margins;
|
||||
const ClickHandlerPtr link;
|
||||
const Fn<void()> updateCallback;
|
||||
bool underDate = true;
|
||||
int lastWidth = 0;
|
||||
QPoint lastPoint;
|
||||
std::unique_ptr<Ui::RippleAnimation> ripple;
|
||||
Ui::Text::String text;
|
||||
};
|
||||
|
||||
bool ViewButton::MediaHasViewButton(not_null<Data::Media*> media) {
|
||||
return media->webpage()
|
||||
? MediaHasViewButton(media->webpage())
|
||||
: false;
|
||||
}
|
||||
|
||||
bool ViewButton::MediaHasViewButton(
|
||||
not_null<WebPageData*> webpage) {
|
||||
const auto type = webpage->type;
|
||||
return (type == WebPageType::Message)
|
||||
|| (type == WebPageType::Group)
|
||||
|| (type == WebPageType::Channel)
|
||||
// || (type == WebPageType::Bot)
|
||||
// || (type == WebPageType::User)
|
||||
|| (type == WebPageType::VoiceChat)
|
||||
|| (type == WebPageType::Livestream)
|
||||
|| ((type == WebPageType::Theme)
|
||||
&& webpage->document
|
||||
&& webpage->document->isTheme())
|
||||
|| ((type == WebPageType::WallPaper)
|
||||
&& webpage->document
|
||||
&& webpage->document->isWallPaper());
|
||||
}
|
||||
|
||||
ViewButton::Inner::Inner(not_null<PeerData*> peer, Fn<void()> updateCallback)
|
||||
: margins(st::historyViewButtonMargins)
|
||||
, link(std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
||||
|
@ -73,6 +125,26 @@ ViewButton::Inner::Inner(not_null<PeerData*> peer, Fn<void()> updateCallback)
|
|||
, text(st::historyViewButtonTextStyle, PeerToPhrase(peer)) {
|
||||
}
|
||||
|
||||
ViewButton::Inner::Inner(
|
||||
not_null<Data::Media*> media,
|
||||
Fn<void()> updateCallback)
|
||||
: margins(st::historyViewButtonMargins)
|
||||
, link(std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto controller = my.sessionWindow.get()) {
|
||||
const auto &data = controller->session().data();
|
||||
const auto webpage = media->webpage();
|
||||
if (!webpage) {
|
||||
return;
|
||||
}
|
||||
HiddenUrlClickHandler::Open(webpage->url, context.other);
|
||||
}
|
||||
}))
|
||||
, updateCallback(std::move(updateCallback))
|
||||
, underDate(false)
|
||||
, text(st::historyViewButtonTextStyle, WebPageToPhrase(media->webpage())) {
|
||||
}
|
||||
|
||||
void ViewButton::Inner::updateMask(int height) {
|
||||
ripple = std::make_unique<Ui::RippleAnimation>(
|
||||
st::defaultRippleAnimation,
|
||||
|
@ -96,6 +168,12 @@ ViewButton::ViewButton(not_null<PeerData*> peer, Fn<void()> updateCallback)
|
|||
: _inner(std::make_unique<Inner>(peer, std::move(updateCallback))) {
|
||||
}
|
||||
|
||||
ViewButton::ViewButton(
|
||||
not_null<Data::Media*> media,
|
||||
Fn<void()> updateCallback)
|
||||
: _inner(std::make_unique<Inner>(media, std::move(updateCallback))) {
|
||||
}
|
||||
|
||||
ViewButton::~ViewButton() {
|
||||
}
|
||||
|
||||
|
@ -169,10 +247,11 @@ bool ViewButton::getState(
|
|||
return true;
|
||||
}
|
||||
|
||||
QRect ViewButton::countSponsoredRect(const QRect &r) const {
|
||||
QRect ViewButton::countRect(const QRect &r) const {
|
||||
const auto dateHeight = (_inner->underDate ? 0 : st::msgDateFont->height);
|
||||
return QRect(
|
||||
r.left(),
|
||||
r.top() + r.height() - height(),
|
||||
r.top() + r.height() - height() - dateHeight,
|
||||
r.width(),
|
||||
height()) - _inner->margins;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "ui/chat/chat_style.h"
|
||||
|
||||
namespace Data {
|
||||
class Media;
|
||||
} // namespace Data
|
||||
|
||||
struct WebPageData;
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
struct TextState;
|
||||
|
@ -16,8 +22,14 @@ struct TextState;
|
|||
class ViewButton {
|
||||
public:
|
||||
ViewButton(not_null<PeerData*> peer, Fn<void()> updateCallback);
|
||||
ViewButton(not_null<Data::Media*> media, Fn<void()> updateCallback);
|
||||
~ViewButton();
|
||||
|
||||
[[nodiscard]] static bool MediaHasViewButton(
|
||||
not_null<Data::Media*> media);
|
||||
[[nodiscard]] static bool MediaHasViewButton(
|
||||
not_null<WebPageData*> webpage);
|
||||
|
||||
[[nodiscard]] int height() const;
|
||||
|
||||
void draw(
|
||||
|
@ -28,7 +40,7 @@ public:
|
|||
[[nodiscard]] const ClickHandlerPtr &link() const;
|
||||
bool checkLink(const ClickHandlerPtr &other, bool pressed);
|
||||
|
||||
[[nodiscard]] QRect countSponsoredRect(const QRect &r) const;
|
||||
[[nodiscard]] QRect countRect(const QRect &r) const;
|
||||
|
||||
[[nodiscard]] bool getState(
|
||||
QPoint point,
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "history/view/history_view_cursor_state.h"
|
||||
#include "history/view/history_view_view_button.h"
|
||||
#include "history/view/media/history_view_media_common.h"
|
||||
#include "history/view/media/history_view_theme_document.h"
|
||||
#include "ui/image/image.h"
|
||||
|
@ -188,7 +189,12 @@ QSize WebPage::countOptimalSize() {
|
|||
_data->url);
|
||||
}
|
||||
|
||||
auto textFloatsAroundInfo = !_asArticle && !_attach && isBubbleBottom();
|
||||
_hasViewButton = ViewButton::MediaHasViewButton(_data);
|
||||
|
||||
const auto textFloatsAroundInfo = !_asArticle
|
||||
&& !_attach
|
||||
&& isBubbleBottom()
|
||||
&& !_hasViewButton;
|
||||
|
||||
// init strings
|
||||
if (_description.isEmpty() && !_data->description.text.isEmpty()) {
|
||||
|
@ -391,6 +397,8 @@ QSize WebPage::countCurrentSize(int newWidth) {
|
|||
} else if (isBubbleBottom() && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > innerWidth + bubble.left() + bubble.right()) {
|
||||
newHeight += bottomInfoPadding();
|
||||
}
|
||||
} else if (_hasViewButton) {
|
||||
newHeight += bottomInfoPadding();
|
||||
}
|
||||
}
|
||||
auto padding = inBubblePadding();
|
||||
|
@ -471,6 +479,8 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
|
|||
bshift += bottomInfoPadding();
|
||||
} else if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > paintw + bubble.left() + bubble.right()) {
|
||||
bshift += bottomInfoPadding();
|
||||
} else if (_hasViewButton) {
|
||||
bshift += bottomInfoPadding();
|
||||
}
|
||||
|
||||
QRect bar(style::rtlrect(st::msgPadding.left(), tshift, st::webPageBar, height() - tshift - bshift, width()));
|
||||
|
|
|
@ -117,6 +117,7 @@ private:
|
|||
mutable std::shared_ptr<Data::PhotoMedia> _photoMedia;
|
||||
|
||||
bool _asArticle = false;
|
||||
bool _hasViewButton = false;
|
||||
int _dataVersion = -1;
|
||||
int _siteNameLines = 0;
|
||||
int _titleLines = 0;
|
||||
|
|
|
@ -751,7 +751,7 @@ historyPollInChosen: icon {{ "poll_select_check", historyFileInIconFg }};
|
|||
historyPollInChosenSelected: icon {{ "poll_select_check", historyFileInIconFgSelected }};
|
||||
|
||||
historyViewButtonHeight: 42px;
|
||||
historyViewButtonMargins: margins(5px, 5px, 5px, 5px);
|
||||
historyViewButtonMargins: margins(13px, 5px, 13px, 5px);
|
||||
historyViewButtonOutline: margins(2px, 2px, 2px, 2px);
|
||||
historyViewButtonTextStyle: semiboldTextStyle;
|
||||
|
||||
|
|
Loading…
Reference in New Issue