2021-10-05 22:18:53 +00:00
|
|
|
/*
|
|
|
|
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/history_view_view_button.h"
|
|
|
|
|
2021-12-23 16:48:36 +00:00
|
|
|
#include "api/api_chat_invite.h"
|
2021-10-10 16:11:08 +00:00
|
|
|
#include "core/application.h"
|
2021-10-05 22:18:53 +00:00
|
|
|
#include "core/click_handler_types.h"
|
2021-10-10 16:11:08 +00:00
|
|
|
#include "data/data_cloud_themes.h"
|
2021-10-07 16:44:33 +00:00
|
|
|
#include "data/data_session.h"
|
|
|
|
#include "data/data_sponsored_messages.h"
|
2021-10-05 22:18:53 +00:00
|
|
|
#include "data/data_user.h"
|
2021-10-10 16:11:08 +00:00
|
|
|
#include "data/data_web_page.h"
|
2021-12-31 12:47:23 +00:00
|
|
|
#include "history/history_item_components.h"
|
2021-10-05 22:18:53 +00:00
|
|
|
#include "history/view/history_view_cursor_state.h"
|
|
|
|
#include "lang/lang_keys.h"
|
2021-10-07 16:44:33 +00:00
|
|
|
#include "main/main_session.h"
|
2021-10-05 22:18:53 +00:00
|
|
|
#include "ui/click_handler.h"
|
|
|
|
#include "ui/effects/ripple_animation.h"
|
2022-09-16 20:23:27 +00:00
|
|
|
#include "ui/painter.h"
|
2021-10-05 22:18:53 +00:00
|
|
|
#include "ui/round_rect.h"
|
|
|
|
#include "ui/text/text_utilities.h" // Ui::Text::ToUpper
|
|
|
|
#include "window/window_session_controller.h"
|
|
|
|
#include "styles/style_chat.h"
|
|
|
|
#include "styles/style_widgets.h"
|
|
|
|
#include "styles/style_window.h"
|
|
|
|
|
|
|
|
namespace HistoryView {
|
|
|
|
namespace {
|
|
|
|
|
2021-12-31 12:47:23 +00:00
|
|
|
using SponsoredType = HistoryMessageSponsored::Type;
|
|
|
|
|
|
|
|
inline auto SponsoredPhrase(SponsoredType type) {
|
2021-10-05 22:18:53 +00:00
|
|
|
const auto phrase = [&] {
|
2021-12-31 12:47:23 +00:00
|
|
|
switch (type) {
|
2021-12-31 13:05:20 +00:00
|
|
|
case SponsoredType::User: return tr::lng_view_button_user;
|
2021-12-31 12:47:23 +00:00
|
|
|
case SponsoredType::Group: return tr::lng_view_button_group;
|
|
|
|
case SponsoredType::Broadcast: return tr::lng_view_button_channel;
|
2021-12-31 13:05:20 +00:00
|
|
|
case SponsoredType::Post: return tr::lng_view_button_message;
|
|
|
|
case SponsoredType::Bot: return tr::lng_view_button_bot;
|
2021-10-05 22:18:53 +00:00
|
|
|
}
|
2021-12-31 12:47:23 +00:00
|
|
|
Unexpected("SponsoredType in SponsoredPhrase.");
|
|
|
|
}();
|
|
|
|
return Ui::Text::Upper(phrase(tr::now));
|
2021-10-05 22:18:53 +00:00
|
|
|
}
|
|
|
|
|
2021-10-10 16:11:08 +00:00
|
|
|
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)
|
2021-10-12 12:50:18 +00:00
|
|
|
: (type == WebPageType::GroupWithRequest
|
|
|
|
|| type == WebPageType::ChannelWithRequest)
|
|
|
|
? tr::lng_view_button_request_join(tr::now)
|
2021-10-10 16:11:08 +00:00
|
|
|
: (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());
|
|
|
|
}
|
|
|
|
|
2022-02-01 12:49:22 +00:00
|
|
|
[[nodiscard]] ClickHandlerPtr MakeWebPageClickHandler(
|
|
|
|
not_null<Data::Media*> media) {
|
|
|
|
Expects(media->webpage() != nullptr);
|
|
|
|
|
|
|
|
const auto url = media->webpage()->url;
|
|
|
|
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
|
|
|
const auto my = context.other.value<ClickHandlerContext>();
|
|
|
|
if (const auto controller = my.sessionWindow.get()) {
|
|
|
|
HiddenUrlClickHandler::Open(url, context.other);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-10-05 22:18:53 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
struct ViewButton::Inner {
|
2021-12-31 12:47:23 +00:00
|
|
|
Inner(
|
|
|
|
not_null<HistoryMessageSponsored*> sponsored,
|
|
|
|
Fn<void()> updateCallback);
|
2021-10-10 16:11:08 +00:00
|
|
|
Inner(not_null<Data::Media*> media, Fn<void()> updateCallback);
|
2021-12-31 12:47:23 +00:00
|
|
|
|
2021-10-05 22:18:53 +00:00
|
|
|
void updateMask(int height);
|
|
|
|
void toggleRipple(bool pressed);
|
|
|
|
|
|
|
|
const style::margins &margins;
|
|
|
|
const ClickHandlerPtr link;
|
|
|
|
const Fn<void()> updateCallback;
|
2021-12-07 08:15:30 +00:00
|
|
|
bool belowInfo = true;
|
2021-10-05 22:18:53 +00:00
|
|
|
int lastWidth = 0;
|
|
|
|
QPoint lastPoint;
|
|
|
|
std::unique_ptr<Ui::RippleAnimation> ripple;
|
|
|
|
Ui::Text::String text;
|
|
|
|
};
|
|
|
|
|
2021-10-10 16:11:08 +00:00
|
|
|
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)
|
2022-01-31 13:17:58 +00:00
|
|
|
|| (type == WebPageType::User)
|
2021-10-10 16:11:08 +00:00
|
|
|
|| (type == WebPageType::VoiceChat)
|
|
|
|
|| (type == WebPageType::Livestream)
|
|
|
|
|| ((type == WebPageType::Theme)
|
|
|
|
&& webpage->document
|
|
|
|
&& webpage->document->isTheme())
|
|
|
|
|| ((type == WebPageType::WallPaper)
|
|
|
|
&& webpage->document
|
|
|
|
&& webpage->document->isWallPaper());
|
|
|
|
}
|
|
|
|
|
2021-12-31 12:47:23 +00:00
|
|
|
ViewButton::Inner::Inner(
|
|
|
|
not_null<HistoryMessageSponsored*> sponsored,
|
|
|
|
Fn<void()> updateCallback)
|
2021-10-05 22:18:53 +00:00
|
|
|
: margins(st::historyViewButtonMargins)
|
2021-10-07 16:16:42 +00:00
|
|
|
, link(std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
|
|
|
const auto my = context.other.value<ClickHandlerContext>();
|
|
|
|
if (const auto controller = my.sessionWindow.get()) {
|
2021-10-07 16:44:33 +00:00
|
|
|
const auto &data = controller->session().data();
|
2021-12-31 12:47:23 +00:00
|
|
|
const auto itemId = my.itemId;
|
|
|
|
const auto details = data.sponsoredMessages().lookupDetails(itemId);
|
|
|
|
if (details.hash) {
|
|
|
|
Api::CheckChatInvite(controller, *details.hash);
|
|
|
|
} else if (details.peer) {
|
|
|
|
controller->showPeerHistory(
|
|
|
|
details.peer,
|
|
|
|
Window::SectionShow::Way::Forward,
|
|
|
|
details.msgId);
|
2021-12-23 16:48:36 +00:00
|
|
|
}
|
2021-10-07 16:16:42 +00:00
|
|
|
}
|
|
|
|
}))
|
2021-10-05 22:18:53 +00:00
|
|
|
, updateCallback(std::move(updateCallback))
|
2021-12-31 12:47:23 +00:00
|
|
|
, text(st::historyViewButtonTextStyle, SponsoredPhrase(sponsored->type)) {
|
2021-10-05 22:18:53 +00:00
|
|
|
}
|
|
|
|
|
2021-10-10 16:11:08 +00:00
|
|
|
ViewButton::Inner::Inner(
|
|
|
|
not_null<Data::Media*> media,
|
|
|
|
Fn<void()> updateCallback)
|
|
|
|
: margins(st::historyViewButtonMargins)
|
2022-02-01 12:49:22 +00:00
|
|
|
, link(MakeWebPageClickHandler(media))
|
2021-10-10 16:11:08 +00:00
|
|
|
, updateCallback(std::move(updateCallback))
|
2021-12-07 08:15:30 +00:00
|
|
|
, belowInfo(false)
|
2021-10-10 16:11:08 +00:00
|
|
|
, text(st::historyViewButtonTextStyle, WebPageToPhrase(media->webpage())) {
|
|
|
|
}
|
|
|
|
|
2021-10-05 22:18:53 +00:00
|
|
|
void ViewButton::Inner::updateMask(int height) {
|
|
|
|
ripple = std::make_unique<Ui::RippleAnimation>(
|
|
|
|
st::defaultRippleAnimation,
|
2022-10-03 11:11:05 +00:00
|
|
|
Ui::RippleAnimation::RoundRectMask(
|
2021-10-05 22:18:53 +00:00
|
|
|
QSize(lastWidth, height - margins.top() - margins.bottom()),
|
|
|
|
st::roundRadiusLarge),
|
|
|
|
updateCallback);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewButton::Inner::toggleRipple(bool pressed) {
|
|
|
|
if (ripple) {
|
|
|
|
if (pressed) {
|
|
|
|
ripple->add(lastPoint);
|
|
|
|
} else {
|
|
|
|
ripple->lastStop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-31 12:47:23 +00:00
|
|
|
ViewButton::ViewButton(
|
|
|
|
not_null<HistoryMessageSponsored*> sponsored,
|
|
|
|
Fn<void()> updateCallback)
|
|
|
|
: _inner(std::make_unique<Inner>(sponsored, std::move(updateCallback))) {
|
2021-10-05 22:18:53 +00:00
|
|
|
}
|
|
|
|
|
2021-10-10 16:11:08 +00:00
|
|
|
ViewButton::ViewButton(
|
|
|
|
not_null<Data::Media*> media,
|
|
|
|
Fn<void()> updateCallback)
|
|
|
|
: _inner(std::make_unique<Inner>(media, std::move(updateCallback))) {
|
|
|
|
}
|
|
|
|
|
2021-10-05 22:18:53 +00:00
|
|
|
ViewButton::~ViewButton() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewButton::resized() const {
|
|
|
|
_inner->updateMask(height());
|
|
|
|
}
|
|
|
|
|
|
|
|
int ViewButton::height() const {
|
|
|
|
return st::historyViewButtonHeight;
|
|
|
|
}
|
|
|
|
|
2021-12-07 08:15:30 +00:00
|
|
|
bool ViewButton::belowMessageInfo() const {
|
|
|
|
return _inner->belowInfo;
|
|
|
|
}
|
|
|
|
|
2021-10-05 22:18:53 +00:00
|
|
|
void ViewButton::draw(
|
|
|
|
Painter &p,
|
|
|
|
const QRect &r,
|
|
|
|
const Ui::ChatPaintContext &context) {
|
|
|
|
const auto stm = context.messageStyle();
|
|
|
|
|
|
|
|
if (_inner->ripple && !_inner->ripple->empty()) {
|
|
|
|
const auto opacity = p.opacity();
|
|
|
|
p.setOpacity(st::historyPollRippleOpacity);
|
|
|
|
const auto colorOverride = &stm->msgWaveformInactive->c;
|
|
|
|
_inner->ripple->paint(p, r.left(), r.top(), r.width(), colorOverride);
|
|
|
|
p.setOpacity(opacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
p.save();
|
|
|
|
{
|
|
|
|
PainterHighQualityEnabler hq(p);
|
2021-10-07 07:38:07 +00:00
|
|
|
auto pen = stm->fwdTextPalette.linkFg->p;
|
|
|
|
pen.setWidth(st::lineWidth);
|
|
|
|
p.setPen(pen);
|
2021-10-05 22:18:53 +00:00
|
|
|
p.setBrush(Qt::NoBrush);
|
2021-11-01 09:08:43 +00:00
|
|
|
const auto half = st::lineWidth / 2.;
|
|
|
|
const auto rf = QRectF(r).marginsRemoved({ half, half, half, half });
|
|
|
|
p.drawRoundedRect(rf, st::roundRadiusLarge, st::roundRadiusLarge);
|
2021-10-05 22:18:53 +00:00
|
|
|
|
|
|
|
_inner->text.drawElided(
|
|
|
|
p,
|
|
|
|
r.left(),
|
|
|
|
r.top() + (r.height() - _inner->text.minHeight()) / 2,
|
|
|
|
r.width(),
|
|
|
|
1,
|
|
|
|
style::al_center);
|
|
|
|
}
|
|
|
|
p.restore();
|
|
|
|
if (_inner->lastWidth != r.width()) {
|
|
|
|
_inner->lastWidth = r.width();
|
|
|
|
resized();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const ClickHandlerPtr &ViewButton::link() const {
|
|
|
|
return _inner->link;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ViewButton::checkLink(const ClickHandlerPtr &other, bool pressed) {
|
|
|
|
if (_inner->link != other) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
_inner->toggleRipple(pressed);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ViewButton::getState(
|
|
|
|
QPoint point,
|
|
|
|
const QRect &g,
|
|
|
|
not_null<TextState*> outResult) const {
|
|
|
|
if (!g.contains(point)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
outResult->link = _inner->link;
|
|
|
|
_inner->lastPoint = point - g.topLeft();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-10-10 16:11:08 +00:00
|
|
|
QRect ViewButton::countRect(const QRect &r) const {
|
2021-10-05 22:18:53 +00:00
|
|
|
return QRect(
|
|
|
|
r.left(),
|
2021-12-07 08:15:30 +00:00
|
|
|
r.top() + r.height() - height(),
|
2021-10-05 22:18:53 +00:00
|
|
|
r.width(),
|
|
|
|
height()) - _inner->margins;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace HistoryView
|