mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 13:17:08 +02:00
Show "premium required" information in chat.
This commit is contained in:
parent
c765bee0cd
commit
e5cda0e2b1
27 changed files with 566 additions and 200 deletions
|
@ -752,6 +752,8 @@ PRIVATE
|
|||
history/view/reactions/history_view_reactions_strip.h
|
||||
history/view/reactions/history_view_reactions_tabs.cpp
|
||||
history/view/reactions/history_view_reactions_tabs.h
|
||||
history/view/history_view_about_view.cpp
|
||||
history/view/history_view_about_view.h
|
||||
history/view/history_view_bottom_info.cpp
|
||||
history/view/history_view_bottom_info.h
|
||||
history/view/history_view_contact_status.cpp
|
||||
|
|
BIN
Telegram/Resources/icons/chat/large_lockedchat.png
Normal file
BIN
Telegram/Resources/icons/chat/large_lockedchat.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/chat/large_lockedchat@2x.png
Normal file
BIN
Telegram/Resources/icons/chat/large_lockedchat@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
Telegram/Resources/icons/chat/large_lockedchat@3x.png
Normal file
BIN
Telegram/Resources/icons/chat/large_lockedchat@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
|
@ -3612,6 +3612,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
"lng_restricted_send_voice_messages" = "{user} restricted sending of voice messages to them.";
|
||||
"lng_restricted_send_video_messages" = "{user} restricted sending of video messages to them.";
|
||||
"lng_restricted_send_non_premium" = "Only Premium users can message {user}.";
|
||||
"lng_restricted_send_non_premium_more" = "Learn more...";
|
||||
|
||||
"lng_send_non_premium_text" = "Subscribe to **Premium**\n to message {user}.";
|
||||
"lng_send_non_premium_go" = "Go Premium";
|
||||
"lng_send_non_premium_story" = "Replies restricted";
|
||||
"lng_send_non_premium_unlock" = "Unlock";
|
||||
"lng_send_non_premium_story_toast" = "You need a **Premium** subscription to reply to **{user}'s** stories.";
|
||||
"lng_send_non_premium_message_toast" = "**{user}** only accepts messages from contacts and **Premium** users.";
|
||||
"lng_send_non_premium_toast_button" = "View";
|
||||
|
||||
"lng_exceptions_list_title" = "Exceptions";
|
||||
"lng_removed_list_title" = "Removed users";
|
||||
|
|
|
@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "mainwindow.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
@ -904,3 +905,68 @@ base::unique_qptr<Ui::RpWidget> CreateDisabledFieldView(
|
|||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::RpWidget> TextErrorSendRestriction(
|
||||
QWidget *parent,
|
||||
const QString &text) {
|
||||
auto result = base::make_unique_q<Ui::RpWidget>(parent);
|
||||
const auto raw = result.get();
|
||||
const auto label = CreateChild<Ui::FlatLabel>(
|
||||
result.get(),
|
||||
text,
|
||||
st::historySendPremiumRequired);
|
||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
raw->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
QPainter(raw).fillRect(clip, st::windowBg);
|
||||
}, raw->lifetime());
|
||||
raw->sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
const auto &st = st::historyComposeField;
|
||||
const auto width = size.width();
|
||||
const auto margins = (st.textMargins + st.placeholderMargins);
|
||||
const auto available = width - margins.left() - margins.right();
|
||||
label->resizeToWidth(available);
|
||||
label->moveToLeft(
|
||||
margins.left(),
|
||||
(size.height() - label->height()) / 2,
|
||||
width);
|
||||
}, label->lifetime());
|
||||
return result;
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::RpWidget> PremiumRequiredSendRestriction(
|
||||
QWidget *parent,
|
||||
not_null<UserData*> user,
|
||||
not_null<Window::SessionController*> controller) {
|
||||
auto result = base::make_unique_q<Ui::RpWidget>(parent);
|
||||
const auto raw = result.get();
|
||||
const auto label = CreateChild<Ui::FlatLabel>(
|
||||
result.get(),
|
||||
tr::lng_restricted_send_non_premium(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->shortName()),
|
||||
st::historySendPremiumRequired);
|
||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
const auto link = CreateChild<Ui::LinkButton>(
|
||||
result.get(),
|
||||
tr::lng_restricted_send_non_premium_more(tr::now));
|
||||
raw->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
QPainter(raw).fillRect(clip, st::windowBg);
|
||||
}, raw->lifetime());
|
||||
raw->widthValue(
|
||||
) | rpl::start_with_next([=](int width) {
|
||||
const auto &st = st::historyComposeField;
|
||||
const auto margins = (st.textMargins + st.placeholderMargins);
|
||||
const auto available = width - margins.left() - margins.right();
|
||||
label->resizeToWidth(available);
|
||||
label->moveToLeft(margins.left(), margins.top(), width);
|
||||
link->move(
|
||||
(width - link->width()) / 2,
|
||||
label->y() + label->height());
|
||||
}, label->lifetime());
|
||||
link->setClickedCallback([=] {
|
||||
Settings::ShowPremium(controller, u"require_premium"_q);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -143,3 +143,10 @@ private:
|
|||
[[nodiscard]] base::unique_qptr<Ui::RpWidget> CreateDisabledFieldView(
|
||||
QWidget *parent,
|
||||
not_null<PeerData*> peer);
|
||||
[[nodiscard]] base::unique_qptr<Ui::RpWidget> TextErrorSendRestriction(
|
||||
QWidget *parent,
|
||||
const QString &text);
|
||||
[[nodiscard]] base::unique_qptr<Ui::RpWidget> PremiumRequiredSendRestriction(
|
||||
QWidget *parent,
|
||||
not_null<UserData*> user,
|
||||
not_null<Window::SessionController*> controller);
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_peer_values.h"
|
||||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
|
||||
namespace {
|
||||
|
@ -113,6 +114,9 @@ bool CanSendAnyOf(
|
|||
if (const auto user = peer->asUser()) {
|
||||
if (user->isInaccessible() || user->isRepliesChat()) {
|
||||
return false;
|
||||
} else if (user->meRequiresPremiumToWrite()
|
||||
&& !user->session().premium()) {
|
||||
return false;
|
||||
} else if (rights
|
||||
& ~(ChatRestriction::SendVoiceMessages
|
||||
| ChatRestriction::SendVideoMessages
|
||||
|
@ -167,6 +171,13 @@ std::optional<QString> RestrictionError(
|
|||
using Flag = ChatRestriction;
|
||||
if (const auto restricted = peer->amRestricted(restriction)) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (user->meRequiresPremiumToWrite()
|
||||
&& !user->session().premium()) {
|
||||
return tr::lng_restricted_send_non_premium(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->shortName());
|
||||
}
|
||||
const auto result = (restriction == Flag::SendVoiceMessages)
|
||||
? tr::lng_restricted_send_voice_messages(
|
||||
tr::now,
|
||||
|
|
|
@ -1101,6 +1101,9 @@ Data::RestrictionCheckResult PeerData::amRestricted(
|
|||
}
|
||||
};
|
||||
if (const auto user = asUser()) {
|
||||
if (user->meRequiresPremiumToWrite() && !user->session().premium()) {
|
||||
return Result::Explicit();
|
||||
}
|
||||
return (right == ChatRestriction::SendVoiceMessages
|
||||
|| right == ChatRestriction::SendVideoMessages)
|
||||
? ((user->flags() & UserDataFlag::VoiceMessagesForbidden)
|
||||
|
|
|
@ -217,13 +217,24 @@ inline auto DefaultRestrictionValue(
|
|||
using namespace rpl::mappers;
|
||||
const auto other = rights & ~(ChatRestriction::SendVoiceMessages
|
||||
| ChatRestriction::SendVideoMessages);
|
||||
auto allowedAny = PeerFlagsValue(
|
||||
user,
|
||||
(UserDataFlag::Deleted | UserDataFlag::MeRequiresPremiumToWrite)
|
||||
) | rpl::map([=](UserDataFlags flags) {
|
||||
return (flags & UserDataFlag::Deleted)
|
||||
? rpl::single(false)
|
||||
: !(flags & UserDataFlag::MeRequiresPremiumToWrite)
|
||||
? rpl::single(true)
|
||||
: AmPremiumValue(&user->session());
|
||||
}) | rpl::flatten_latest();
|
||||
if (other) {
|
||||
return PeerFlagValue(user, UserDataFlag::Deleted)
|
||||
| rpl::map(!_1);
|
||||
return std::move(allowedAny);
|
||||
}
|
||||
const auto mask = UserDataFlag::Deleted
|
||||
| UserDataFlag::VoiceMessagesForbidden;
|
||||
return PeerFlagsValue(user, mask) | rpl::map(!_1);
|
||||
const auto mask = UserDataFlag::VoiceMessagesForbidden;
|
||||
return rpl::combine(
|
||||
std::move(allowedAny),
|
||||
PeerFlagValue(user, mask),
|
||||
_1 && !_2);
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
const auto mask = ChatDataFlag()
|
||||
| ChatDataFlag::Deactivated
|
||||
|
|
|
@ -520,6 +520,7 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
|||
| Flag::Premium
|
||||
| Flag::Support
|
||||
| Flag::SomeRequirePremiumToWrite
|
||||
| Flag::MeRequiresPremiumToWrite AssertIsDebug()
|
||||
| Flag::RequirePremiumToWriteKnown
|
||||
| (!minimal
|
||||
? Flag::Contact
|
||||
|
@ -542,7 +543,7 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
|||
| (data.is_premium() ? Flag::Premium : Flag())
|
||||
| (data.is_support() ? Flag::Support : Flag())
|
||||
| (data.is_contact_require_premium()
|
||||
? (Flag::SomeRequirePremiumToWrite
|
||||
? ((Flag::SomeRequirePremiumToWrite | Flag::MeRequiresPremiumToWrite) AssertIsDebug()
|
||||
| (result->someRequirePremiumToWrite()
|
||||
? (result->requirePremiumToWriteKnown()
|
||||
? Flag::RequirePremiumToWriteKnown
|
||||
|
|
|
@ -300,8 +300,8 @@ enum class MessageFlag : uint64 {
|
|||
OnlyEmojiAndSpaces = (1ULL << 35),
|
||||
OnlyEmojiAndSpacesSet = (1ULL << 36),
|
||||
|
||||
// Fake message with bot cover and information.
|
||||
FakeBotAbout = (1ULL << 37),
|
||||
// Fake message with some info, like bot cover and information.
|
||||
FakeAboutView = (1ULL << 37),
|
||||
|
||||
StoryItem = (1ULL << 38),
|
||||
|
||||
|
|
|
@ -506,7 +506,7 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
|
|||
| Flag::VoiceMessagesForbidden
|
||||
| Flag::ReadDatesPrivate
|
||||
| Flag::RequirePremiumToWriteKnown
|
||||
| Flag::MeRequiresPremiumToWrite;
|
||||
/*| Flag::MeRequiresPremiumToWrite*/; AssertIsDebug()
|
||||
user->setFlags((user->flags() & ~mask)
|
||||
| (update.is_phone_calls_private()
|
||||
? Flag::PhoneCallsPrivate
|
||||
|
|
|
@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "history/admin_log/history_admin_log_item.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "history/view/controls/history_view_forward_panel.h"
|
||||
#include "history/view/controls/history_view_draft_options.h"
|
||||
|
@ -17,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/media/history_view_web_page.h"
|
||||
#include "history/view/reactions/history_view_reactions_button.h"
|
||||
#include "history/view/reactions/history_view_reactions_selector.h"
|
||||
#include "history/view/history_view_about_view.h"
|
||||
#include "history/view/history_view_message.h"
|
||||
#include "history/view/history_view_service_message.h"
|
||||
#include "history/view/history_view_cursor_state.h"
|
||||
|
@ -305,102 +305,6 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class HistoryInner::BotAbout final : public ClickHandlerHost {
|
||||
public:
|
||||
BotAbout(
|
||||
not_null<History*> history,
|
||||
not_null<HistoryView::ElementDelegate*> delegate);
|
||||
|
||||
[[nodiscard]] not_null<History*> history() const;
|
||||
[[nodiscard]] HistoryView::Element *view() const;
|
||||
[[nodiscard]] HistoryItem *item() const;
|
||||
|
||||
bool refresh();
|
||||
|
||||
int top = 0;
|
||||
int height = 0;
|
||||
|
||||
private:
|
||||
const not_null<History*> _history;
|
||||
const not_null<HistoryView::ElementDelegate*> _delegate;
|
||||
AdminLog::OwnedItem _item;
|
||||
int _version = 0;
|
||||
|
||||
};
|
||||
|
||||
HistoryInner::BotAbout::BotAbout(
|
||||
not_null<History*> history,
|
||||
not_null<HistoryView::ElementDelegate*> delegate)
|
||||
: _history(history)
|
||||
, _delegate(delegate) {
|
||||
}
|
||||
|
||||
not_null<History*> HistoryInner::BotAbout::history() const {
|
||||
return _history;
|
||||
}
|
||||
|
||||
HistoryView::Element *HistoryInner::BotAbout::view() const {
|
||||
return _item.get();
|
||||
}
|
||||
|
||||
HistoryItem *HistoryInner::BotAbout::item() const {
|
||||
if (const auto element = view()) {
|
||||
return element->data();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool HistoryInner::BotAbout::refresh() {
|
||||
const auto bot = _history->peer->asUser();
|
||||
const auto info = bot ? bot->botInfo.get() : nullptr;
|
||||
if (!info) {
|
||||
if (_item) {
|
||||
_item = {};
|
||||
return true;
|
||||
}
|
||||
_version = 0;
|
||||
return false;
|
||||
}
|
||||
const auto version = info->descriptionVersion;
|
||||
if (_version == version) {
|
||||
return false;
|
||||
}
|
||||
_version = version;
|
||||
|
||||
const auto flags = MessageFlag::FakeBotAbout
|
||||
| MessageFlag::FakeHistoryItem
|
||||
| MessageFlag::Local;
|
||||
const auto postAuthor = QString();
|
||||
const auto date = TimeId(0);
|
||||
const auto replyTo = FullReplyTo();
|
||||
const auto viaBotId = UserId(0);
|
||||
const auto groupedId = uint64(0);
|
||||
const auto textWithEntities = TextUtilities::ParseEntities(
|
||||
info->description,
|
||||
Ui::ItemTextBotNoMonoOptions().flags);
|
||||
const auto make = [&](auto &&a, auto &&b, auto &&...other) {
|
||||
return _history->makeMessage(
|
||||
_history->nextNonHistoryEntryId(),
|
||||
flags,
|
||||
replyTo,
|
||||
viaBotId,
|
||||
date,
|
||||
bot->id,
|
||||
postAuthor,
|
||||
std::forward<decltype(a)>(a),
|
||||
std::forward<decltype(b)>(b),
|
||||
HistoryMessageMarkupData(),
|
||||
std::forward<decltype(other)>(other)...);
|
||||
};
|
||||
const auto item = info->document
|
||||
? make(info->document, textWithEntities)
|
||||
: info->photo
|
||||
? make(info->photo, textWithEntities)
|
||||
: make(textWithEntities, MTP_messageMediaEmpty(), groupedId);
|
||||
_item = AdminLog::OwnedItem(_delegate, item);
|
||||
return true;
|
||||
}
|
||||
|
||||
HistoryInner::HistoryInner(
|
||||
not_null<HistoryWidget*> historyWidget,
|
||||
not_null<Ui::ScrollArea*> scroll,
|
||||
|
@ -447,7 +351,7 @@ HistoryInner::HistoryInner(
|
|||
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
|
||||
notifyIsBotChanged();
|
||||
refreshAboutView();
|
||||
|
||||
setMouseTracking(true);
|
||||
_controller->gifPauseLevelChanged(
|
||||
|
@ -1011,10 +915,10 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
|||
|
||||
const auto historyDisplayedEmpty = _history->isDisplayedEmpty()
|
||||
&& (!_migrated || _migrated->isDisplayedEmpty());
|
||||
if (const auto view = _botAbout ? _botAbout->view() : nullptr) {
|
||||
if (clip.y() < _botAbout->top + _botAbout->height
|
||||
&& clip.y() + clip.height() > _botAbout->top) {
|
||||
const auto top = _botAbout->top;
|
||||
if (const auto view = _aboutView ? _aboutView->view() : nullptr) {
|
||||
if (clip.y() < _aboutView->top + _aboutView->height
|
||||
&& clip.y() + clip.height() > _aboutView->top) {
|
||||
const auto top = _aboutView->top;
|
||||
context.translate(0, -top);
|
||||
context.selection = computeRenderSelection(&_selected, view);
|
||||
p.translate(0, top);
|
||||
|
@ -3066,8 +2970,8 @@ void HistoryInner::recountHistoryGeometry() {
|
|||
auto oldHistoryPaddingTop = qMax(
|
||||
visibleHeight - historyHeight() - st::historyPaddingBottom,
|
||||
0);
|
||||
if (_botAbout) {
|
||||
accumulate_max(oldHistoryPaddingTop, _botAbout->height);
|
||||
if (_aboutView) {
|
||||
accumulate_max(oldHistoryPaddingTop, _aboutView->height);
|
||||
}
|
||||
|
||||
updateBotInfo(false);
|
||||
|
@ -3095,20 +2999,20 @@ void HistoryInner::recountHistoryGeometry() {
|
|||
}
|
||||
}
|
||||
|
||||
if (const auto view = _botAbout ? _botAbout->view() : nullptr) {
|
||||
_botAbout->height = view->resizeGetHeight(_contentWidth);
|
||||
_botAbout->top = qMin(
|
||||
_historyPaddingTop - _botAbout->height,
|
||||
qMax(0, (_scroll->height() - _botAbout->height) / 2));
|
||||
} else if (_botAbout) {
|
||||
_botAbout->top = _botAbout->height = 0;
|
||||
if (const auto view = _aboutView ? _aboutView->view() : nullptr) {
|
||||
_aboutView->height = view->resizeGetHeight(_contentWidth);
|
||||
_aboutView->top = qMin(
|
||||
_historyPaddingTop - _aboutView->height,
|
||||
qMax(0, (_scroll->height() - _aboutView->height) / 2));
|
||||
} else if (_aboutView) {
|
||||
_aboutView->top = _aboutView->height = 0;
|
||||
}
|
||||
|
||||
auto newHistoryPaddingTop = qMax(
|
||||
visibleHeight - historyHeight() - st::historyPaddingBottom,
|
||||
0);
|
||||
if (_botAbout) {
|
||||
accumulate_max(newHistoryPaddingTop, _botAbout->height);
|
||||
if (_aboutView) {
|
||||
accumulate_max(newHistoryPaddingTop, _aboutView->height);
|
||||
}
|
||||
|
||||
auto historyPaddingTopDelta = (newHistoryPaddingTop - oldHistoryPaddingTop);
|
||||
|
@ -3122,13 +3026,13 @@ void HistoryInner::recountHistoryGeometry() {
|
|||
}
|
||||
|
||||
void HistoryInner::updateBotInfo(bool recount) {
|
||||
if (!_botAbout) {
|
||||
if (!_aboutView) {
|
||||
return;
|
||||
} else if (_botAbout->refresh() && recount && _contentWidth > 0) {
|
||||
const auto view = _botAbout->view();
|
||||
} else if (_aboutView->refresh() && recount && _contentWidth > 0) {
|
||||
const auto view = _aboutView->view();
|
||||
const auto now = view ? view->resizeGetHeight(_contentWidth) : 0;
|
||||
if (_botAbout->height != now) {
|
||||
_botAbout->height = now;
|
||||
if (_aboutView->height != now) {
|
||||
_aboutView->height = now;
|
||||
updateSize();
|
||||
}
|
||||
}
|
||||
|
@ -3276,14 +3180,14 @@ void HistoryInner::updateSize() {
|
|||
const auto visibleHeight = _scroll->height();
|
||||
const auto itemsHeight = historyHeight() - _revealHeight;
|
||||
auto newHistoryPaddingTop = qMax(visibleHeight - itemsHeight - st::historyPaddingBottom, 0);
|
||||
if (_botAbout) {
|
||||
accumulate_max(newHistoryPaddingTop, _botAbout->height);
|
||||
if (_aboutView) {
|
||||
accumulate_max(newHistoryPaddingTop, _aboutView->height);
|
||||
}
|
||||
|
||||
if (_botAbout && _botAbout->height > 0) {
|
||||
_botAbout->top = qMin(
|
||||
newHistoryPaddingTop - _botAbout->height,
|
||||
qMax(0, (_scroll->height() - _botAbout->height) / 2));
|
||||
if (_aboutView && _aboutView->height > 0) {
|
||||
_aboutView->top = qMin(
|
||||
newHistoryPaddingTop - _aboutView->height,
|
||||
qMax(0, (_scroll->height() - _aboutView->height) / 2));
|
||||
}
|
||||
|
||||
if (_historyPaddingTop != newHistoryPaddingTop) {
|
||||
|
@ -3327,7 +3231,7 @@ void HistoryInner::leaveEventHook(QEvent *e) {
|
|||
}
|
||||
|
||||
HistoryInner::~HistoryInner() {
|
||||
_botAbout = nullptr;
|
||||
_aboutView = nullptr;
|
||||
for (const auto &item : _animatedStickersPlayed) {
|
||||
if (const auto view = item->mainView()) {
|
||||
if (const auto media = view->media()) {
|
||||
|
@ -3641,11 +3545,11 @@ void HistoryInner::mouseActionUpdate() {
|
|||
const auto reactionView = viewByItem(reactionItem);
|
||||
const auto view = reactionView
|
||||
? reactionView
|
||||
: (_botAbout
|
||||
&& _botAbout->view()
|
||||
&& point.y() >= _botAbout->top
|
||||
&& point.y() < _botAbout->top + _botAbout->view()->height())
|
||||
? _botAbout->view()
|
||||
: (_aboutView
|
||||
&& _aboutView->view()
|
||||
&& point.y() >= _aboutView->top
|
||||
&& point.y() < _aboutView->top + _aboutView->view()->height())
|
||||
? _aboutView->view()
|
||||
: (_curHistory && !_curHistory->isEmpty())
|
||||
? _curHistory->blocks[_curBlock]->messages[_curItem].get()
|
||||
: nullptr;
|
||||
|
@ -4004,8 +3908,8 @@ void HistoryInner::clearChooseReportReason() {
|
|||
auto HistoryInner::viewByItem(const HistoryItem *item) const -> Element* {
|
||||
return !item
|
||||
? nullptr
|
||||
: (_botAbout && _botAbout->item() == item)
|
||||
? _botAbout->view()
|
||||
: (_aboutView && _aboutView->item() == item)
|
||||
? _aboutView->view()
|
||||
: item->mainView();
|
||||
}
|
||||
|
||||
|
@ -4017,8 +3921,8 @@ int HistoryInner::itemTop(const HistoryItem *item) const {
|
|||
int HistoryInner::itemTop(const Element *view) const {
|
||||
if (!view) {
|
||||
return -1;
|
||||
} else if (_botAbout && view == _botAbout->view()) {
|
||||
return _botAbout->top;
|
||||
} else if (_aboutView && view == _aboutView->view()) {
|
||||
return _aboutView->top;
|
||||
} else if (view->data()->mainView() != view) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -4056,17 +3960,27 @@ auto HistoryInner::findViewForPinnedTracking(int top) const
|
|||
return { nullptr, 0 };
|
||||
}
|
||||
|
||||
void HistoryInner::notifyIsBotChanged() {
|
||||
void HistoryInner::refreshAboutView() {
|
||||
if (const auto user = _peer->asUser()) {
|
||||
if (const auto info = user->botInfo.get()) {
|
||||
if (!_botAbout) {
|
||||
_botAbout = std::make_unique<BotAbout>(
|
||||
if (!_aboutView) {
|
||||
_aboutView = std::make_unique<HistoryView::AboutView>(
|
||||
_history,
|
||||
_history->delegateMixin()->delegate());
|
||||
}
|
||||
if (!info->inited) {
|
||||
session().api().requestFullPeer(_peer);
|
||||
}
|
||||
} else if (user->meRequiresPremiumToWrite()
|
||||
&& !user->session().premium()
|
||||
&& !historyHeight()) {
|
||||
if (!_aboutView) {
|
||||
_aboutView = std::make_unique<HistoryView::AboutView>(
|
||||
_history,
|
||||
_history->delegateMixin()->delegate());
|
||||
}
|
||||
} else {
|
||||
_aboutView = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4313,7 +4227,7 @@ void HistoryInner::applyDragSelection(
|
|||
if (!toItems->empty() && toItems->cbegin()->second != FullSelection) {
|
||||
toItems->clear();
|
||||
}
|
||||
const auto botAboutView = _botAbout ? _botAbout->view() : nullptr;
|
||||
const auto botAboutView = _aboutView ? _aboutView->view() : nullptr;
|
||||
if (_dragSelecting) {
|
||||
auto fromblock = (_dragSelFrom != botAboutView)
|
||||
? _dragSelFrom->block()->indexInHistory()
|
||||
|
|
|
@ -36,6 +36,7 @@ class Element;
|
|||
class TranslateTracker;
|
||||
struct PinnedId;
|
||||
struct SelectedQuote;
|
||||
class AboutView;
|
||||
} // namespace HistoryView
|
||||
|
||||
namespace HistoryView::Reactions {
|
||||
|
@ -192,7 +193,7 @@ public:
|
|||
[[nodiscard]] std::pair<Element*, int> findViewForPinnedTracking(
|
||||
int top) const;
|
||||
|
||||
void notifyIsBotChanged();
|
||||
void refreshAboutView();
|
||||
void notifyMigrateUpdated();
|
||||
|
||||
// Ui::AbstractTooltipShower interface.
|
||||
|
@ -234,7 +235,6 @@ private:
|
|||
void onTouchSelect();
|
||||
void onTouchScrollTimer();
|
||||
|
||||
class BotAbout;
|
||||
using ChosenReaction = HistoryView::Reactions::ChosenReaction;
|
||||
using VideoUserpic = Dialogs::Ui::VideoUserpic;
|
||||
using SelectedItems = std::map<HistoryItem*, TextSelection, std::less<>>;
|
||||
|
@ -449,7 +449,7 @@ private:
|
|||
// the first _history message date (just skip it by height).
|
||||
int _historySkipHeight = 0;
|
||||
|
||||
std::unique_ptr<BotAbout> _botAbout;
|
||||
std::unique_ptr<HistoryView::AboutView> _aboutView;
|
||||
std::unique_ptr<HistoryView::EmptyPainter> _emptyPainter;
|
||||
std::unique_ptr<HistoryView::TranslateTracker> _translateTracker;
|
||||
|
||||
|
|
|
@ -314,8 +314,8 @@ public:
|
|||
[[nodiscard]] bool isLocal() const {
|
||||
return _flags & MessageFlag::Local;
|
||||
}
|
||||
[[nodiscard]] bool isFakeBotAbout() const {
|
||||
return _flags & MessageFlag::FakeBotAbout;
|
||||
[[nodiscard]] bool isFakeAboutView() const {
|
||||
return _flags & MessageFlag::FakeAboutView;
|
||||
}
|
||||
[[nodiscard]] bool showSimilarChannels() const {
|
||||
return _flags & MessageFlag::ShowSimilarChannels;
|
||||
|
|
|
@ -577,7 +577,7 @@ HistoryWidget::HistoryWidget(
|
|||
) | rpl::filter([=](not_null<UserData*> user) {
|
||||
return (_peer == user.get());
|
||||
}) | rpl::start_with_next([=](not_null<UserData*> user) {
|
||||
_list->notifyIsBotChanged();
|
||||
_list->refreshAboutView();
|
||||
_list->updateBotInfo();
|
||||
updateControlsVisibility();
|
||||
updateControlsGeometry();
|
||||
|
@ -692,6 +692,17 @@ HistoryWidget::HistoryWidget(
|
|||
scrollToCurrentVoiceMessage(pair.from.contextId(), pair.to);
|
||||
}, lifetime());
|
||||
|
||||
session().user()->flagsValue(
|
||||
) | rpl::start_with_next([=](UserData::Flags::Change change) {
|
||||
if (change.diff & UserData::Flag::Premium) {
|
||||
if (const auto user = _peer ? _peer->asUser() : nullptr) {
|
||||
if (user->meRequiresPremiumToWrite()) {
|
||||
handlePeerUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
using PeerUpdateFlag = Data::PeerUpdate::Flag;
|
||||
session().changes().peerUpdates(
|
||||
PeerUpdateFlag::Rights
|
||||
|
@ -2728,18 +2739,6 @@ bool HistoryWidget::canWriteMessage() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::optional<QString> HistoryWidget::writeRestriction() const {
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
auto result = (_peer && !Data::CanSendAnyOf(_peer, allWithoutPolls))
|
||||
? Data::RestrictionError(_peer, ChatRestriction::SendOther)
|
||||
: std::nullopt;
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void HistoryWidget::updateControlsVisibility() {
|
||||
auto fieldDisabledRemoved = (_fieldDisabled != nullptr);
|
||||
const auto guard = gsl::finally([&] {
|
||||
|
@ -2861,6 +2860,9 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
if (_inlineResults) {
|
||||
_inlineResults->hide();
|
||||
}
|
||||
if (_sendRestriction) {
|
||||
_sendRestriction->hide();
|
||||
}
|
||||
hideFieldIfVisible();
|
||||
} else if (editingMessage() || _canSendMessages) {
|
||||
checkFieldAutocomplete();
|
||||
|
@ -2918,6 +2920,9 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
if (_botMenuButton) {
|
||||
_botMenuButton->show();
|
||||
}
|
||||
if (_sendRestriction) {
|
||||
_sendRestriction->hide();
|
||||
}
|
||||
{
|
||||
auto rightButtonsChanged = false;
|
||||
if (_silent) {
|
||||
|
@ -3019,6 +3024,9 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
if (_inlineResults) {
|
||||
_inlineResults->hide();
|
||||
}
|
||||
if (_sendRestriction) {
|
||||
_sendRestriction->show();
|
||||
}
|
||||
_kbScroll->hide();
|
||||
hideFieldIfVisible();
|
||||
}
|
||||
|
@ -5131,6 +5139,9 @@ void HistoryWidget::moveFieldControls() {
|
|||
_joinChannel->setGeometry(fullWidthButtonRect);
|
||||
_muteUnmute->setGeometry(fullWidthButtonRect);
|
||||
_reportMessages->setGeometry(fullWidthButtonRect);
|
||||
if (_sendRestriction) {
|
||||
_sendRestriction->setGeometry(fullWidthButtonRect);
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::updateFieldSize() {
|
||||
|
@ -5163,7 +5174,7 @@ void HistoryWidget::updateFieldSize() {
|
|||
}
|
||||
|
||||
if (_fieldDisabled) {
|
||||
_fieldDisabled->resize(fieldWidth, fieldHeight());
|
||||
_fieldDisabled->resize(width(), st::historySendSize.height());
|
||||
}
|
||||
if (_field->width() != fieldWidth) {
|
||||
_field->resize(fieldWidth, _field->height());
|
||||
|
@ -5849,6 +5860,46 @@ int HistoryWidget::countAutomaticScrollTop() {
|
|||
return ScrollMax;
|
||||
}
|
||||
|
||||
QString HistoryWidget::computeSendRestriction() const {
|
||||
if (const auto user = _peer ? _peer->asUser() : nullptr) {
|
||||
if (user->meRequiresPremiumToWrite()
|
||||
&& !user->session().premium()) {
|
||||
return u"premium_required"_q;
|
||||
}
|
||||
}
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
const auto error = (_peer && !Data::CanSendAnyOf(_peer, allWithoutPolls))
|
||||
? Data::RestrictionError(_peer, ChatRestriction::SendOther)
|
||||
: std::nullopt;
|
||||
return error ? (u"restriction:"_q + *error) : QString();
|
||||
}
|
||||
|
||||
void HistoryWidget::updateSendRestriction() {
|
||||
const auto restriction = computeSendRestriction();
|
||||
if (_sendRestrictionKey == restriction) {
|
||||
return;
|
||||
}
|
||||
_sendRestrictionKey = restriction;
|
||||
if (restriction.isEmpty()) {
|
||||
_sendRestriction = nullptr;
|
||||
} else if (restriction == u"premium_required"_q) {
|
||||
_sendRestriction = PremiumRequiredSendRestriction(
|
||||
this,
|
||||
_peer->asUser(),
|
||||
controller());
|
||||
} else if (restriction.startsWith(u"restriction:"_q)) {
|
||||
const auto error = restriction.mid(12);
|
||||
_sendRestriction = TextErrorSendRestriction(this, error);
|
||||
} else {
|
||||
Unexpected("Restriction type.");
|
||||
}
|
||||
if (_sendRestriction) {
|
||||
_sendRestriction->show();
|
||||
moveFieldControls();
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::updateHistoryGeometry(
|
||||
bool initial,
|
||||
bool loadedDown,
|
||||
|
@ -5893,8 +5944,8 @@ void HistoryWidget::updateHistoryGeometry(
|
|||
} else {
|
||||
if (editingMessage() || _canSendMessages) {
|
||||
newScrollHeight -= (fieldHeight() + 2 * st::historySendPadding);
|
||||
} else if (writeRestriction().has_value()) {
|
||||
newScrollHeight -= _unblock->height();
|
||||
} else if (_sendRestriction) {
|
||||
newScrollHeight -= _sendRestriction->height();
|
||||
}
|
||||
if (_editMsgId
|
||||
|| replyTo()
|
||||
|
@ -7605,6 +7656,7 @@ void HistoryWidget::fullInfoUpdated() {
|
|||
|
||||
void HistoryWidget::handlePeerUpdate() {
|
||||
bool resize = false;
|
||||
updateSendRestriction();
|
||||
updateHistoryGeometry();
|
||||
if (_peer->isChat() && _peer->asChat()->noParticipantInfo()) {
|
||||
session().api().requestFullPeer(_peer);
|
||||
|
@ -8077,15 +8129,6 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
|||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::drawRestrictedWrite(Painter &p, const QString &error) {
|
||||
auto rect = myrtlrect(0, height() - _unblock->height(), width(), _unblock->height());
|
||||
p.fillRect(rect, st::historyReplyBg);
|
||||
|
||||
p.setFont(st::normalFont);
|
||||
p.setPen(st::windowSubTextFg);
|
||||
p.drawText(rect.marginsRemoved(QMargins(st::historySendPadding, 0, st::historySendPadding, 0)), error, style::al_center);
|
||||
}
|
||||
|
||||
void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int top) const {
|
||||
if (!rect.intersects(myrtlrect(left, top, width() - left, st::normalFont->height))) {
|
||||
return;
|
||||
|
@ -8165,12 +8208,6 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
|
|||
|| _kbShown) {
|
||||
drawField(p, clip);
|
||||
}
|
||||
const auto error = restrictionHidden
|
||||
? std::nullopt
|
||||
: writeRestriction();
|
||||
if (error) {
|
||||
drawRestrictedWrite(p, *error);
|
||||
}
|
||||
} else {
|
||||
const auto w = st::msgServiceFont->width(tr::lng_willbe_history(tr::now))
|
||||
+ st::msgPadding.left()
|
||||
|
|
|
@ -474,7 +474,6 @@ private:
|
|||
[[nodiscard]] MsgId resolveReplyToTopicRootId();
|
||||
[[nodiscard]] Data::ForumTopic *resolveReplyToTopic();
|
||||
[[nodiscard]] bool canWriteMessage() const;
|
||||
std::optional<QString> writeRestriction() const;
|
||||
void orderWidgets();
|
||||
|
||||
[[nodiscard]] InlineBotQuery parseInlineBotQuery() const;
|
||||
|
@ -503,11 +502,8 @@ private:
|
|||
bool editingMessage() const {
|
||||
return _editMsgId != 0;
|
||||
}
|
||||
bool jumpToDialogRow(const Dialogs::RowDescriptor &to);
|
||||
|
||||
void setupShortcuts();
|
||||
bool showNextChat();
|
||||
bool showPreviousChat();
|
||||
|
||||
void handlePeerMigration();
|
||||
|
||||
|
@ -536,7 +532,6 @@ private:
|
|||
const QRect &rect,
|
||||
int left,
|
||||
int top) const;
|
||||
void drawRestrictedWrite(Painter &p, const QString &error);
|
||||
bool paintShowAnimationFrame();
|
||||
|
||||
void updateMouseTracking();
|
||||
|
@ -559,6 +554,8 @@ private:
|
|||
void addMessagesToFront(not_null<PeerData*> peer, const QVector<MTPMessage> &messages);
|
||||
void addMessagesToBack(not_null<PeerData*> peer, const QVector<MTPMessage> &messages);
|
||||
|
||||
void updateSendRestriction();
|
||||
[[nodiscard]] QString computeSendRestriction() const;
|
||||
void updateHistoryGeometry(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 });
|
||||
void updateListSize();
|
||||
void startItemRevealAnimations();
|
||||
|
@ -765,6 +762,8 @@ private:
|
|||
bool _cmdStartShown = false;
|
||||
object_ptr<Ui::InputField> _field;
|
||||
base::unique_qptr<Ui::RpWidget> _fieldDisabled;
|
||||
base::unique_qptr<Ui::RpWidget> _sendRestriction;
|
||||
QString _sendRestrictionKey;
|
||||
Ui::Animations::Simple _inPhotoEditOver;
|
||||
bool _inDetails = false;
|
||||
bool _inPhotoEdit = false;
|
||||
|
|
249
Telegram/SourceFiles/history/view/history_view_about_view.cpp
Normal file
249
Telegram/SourceFiles/history/view/history_view_about_view.cpp
Normal file
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
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_about_view.h"
|
||||
|
||||
#include "core/click_handler_types.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/view/media/history_view_service_box.h"
|
||||
#include "history/view/media/history_view_sticker_player_abstract.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h"
|
||||
#include "history/history_item_reply_markup.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_premium.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/painter.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
namespace HistoryView {
|
||||
namespace {
|
||||
|
||||
class PremiumRequiredBox final : public ServiceBoxContent {
|
||||
public:
|
||||
explicit PremiumRequiredBox(not_null<Element*> parent);
|
||||
~PremiumRequiredBox();
|
||||
|
||||
int width() override;
|
||||
int top() override;
|
||||
QSize size() override;
|
||||
QString title() override;
|
||||
TextWithEntities subtitle() override;
|
||||
int buttonSkip() override;
|
||||
rpl::producer<QString> button() override;
|
||||
void draw(
|
||||
Painter &p,
|
||||
const PaintContext &context,
|
||||
const QRect &geometry) override;
|
||||
ClickHandlerPtr createViewLink() override;
|
||||
|
||||
bool hideServiceText() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
void stickerClearLoopPlayed() override;
|
||||
std::unique_ptr<StickerPlayer> stickerTakePlayer(
|
||||
not_null<DocumentData*> data,
|
||||
const Lottie::ColorReplacements *replacements) override;
|
||||
|
||||
bool hasHeavyPart() override;
|
||||
void unloadHeavyPart() override;
|
||||
|
||||
private:
|
||||
const not_null<Element*> _parent;
|
||||
|
||||
};
|
||||
|
||||
PremiumRequiredBox::PremiumRequiredBox(not_null<Element*> parent)
|
||||
: _parent(parent) {
|
||||
}
|
||||
|
||||
PremiumRequiredBox::~PremiumRequiredBox() = default;
|
||||
|
||||
int PremiumRequiredBox::width() {
|
||||
return st::premiumRequiredWidth;
|
||||
}
|
||||
|
||||
int PremiumRequiredBox::top() {
|
||||
return st::msgServiceGiftBoxButtonMargins.top();
|
||||
}
|
||||
|
||||
QSize PremiumRequiredBox::size() {
|
||||
return { st::msgServicePhotoWidth, st::msgServicePhotoWidth };
|
||||
}
|
||||
|
||||
QString PremiumRequiredBox::title() {
|
||||
return QString();
|
||||
}
|
||||
|
||||
int PremiumRequiredBox::buttonSkip() {
|
||||
return st::storyMentionButtonSkip;
|
||||
}
|
||||
|
||||
rpl::producer<QString> PremiumRequiredBox::button() {
|
||||
return tr::lng_send_non_premium_go();
|
||||
}
|
||||
|
||||
TextWithEntities PremiumRequiredBox::subtitle() {
|
||||
return _parent->data()->notificationText();
|
||||
}
|
||||
|
||||
ClickHandlerPtr PremiumRequiredBox::createViewLink() {
|
||||
const auto itemId = _parent->data()->fullId();
|
||||
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto controller = my.sessionWindow.get()) {
|
||||
Settings::ShowPremium(controller, u"require_premium"_q);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PremiumRequiredBox::draw(
|
||||
Painter &p,
|
||||
const PaintContext &context,
|
||||
const QRect &geometry) {
|
||||
const auto padding = (geometry.width() - st::premiumRequiredCircle) / 2;
|
||||
const auto size = geometry.width() - 2 * padding;
|
||||
p.setBrush(context.st->msgServiceBg()); // ?
|
||||
p.setPen(Qt::NoPen);
|
||||
p.drawEllipse(geometry);
|
||||
st::premiumRequiredIcon.paintInCenter(p, geometry);
|
||||
}
|
||||
|
||||
void PremiumRequiredBox::stickerClearLoopPlayed() {
|
||||
}
|
||||
|
||||
std::unique_ptr<StickerPlayer> PremiumRequiredBox::stickerTakePlayer(
|
||||
not_null<DocumentData*> data,
|
||||
const Lottie::ColorReplacements *replacements) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool PremiumRequiredBox::hasHeavyPart() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void PremiumRequiredBox::unloadHeavyPart() {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AboutView::AboutView(
|
||||
not_null<History*> history,
|
||||
not_null<ElementDelegate*> delegate)
|
||||
: _history(history)
|
||||
, _delegate(delegate) {
|
||||
}
|
||||
|
||||
not_null<History*> AboutView::history() const {
|
||||
return _history;
|
||||
}
|
||||
|
||||
Element *AboutView::view() const {
|
||||
return _item.get();
|
||||
}
|
||||
|
||||
HistoryItem *AboutView::item() const {
|
||||
if (const auto element = view()) {
|
||||
return element->data();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AboutView::refresh() {
|
||||
const auto bot = _history->peer->asUser();
|
||||
const auto info = bot ? bot->botInfo.get() : nullptr;
|
||||
if (!info) {
|
||||
if (bot
|
||||
&& bot->meRequiresPremiumToWrite()
|
||||
&& !bot->session().premium()
|
||||
&& _history->isEmpty()) {
|
||||
if (_item) {
|
||||
return false;
|
||||
}
|
||||
_item = makePremiumRequired();
|
||||
return true;
|
||||
}
|
||||
if (_item) {
|
||||
_item = {};
|
||||
return true;
|
||||
}
|
||||
_version = 0;
|
||||
return false;
|
||||
}
|
||||
const auto version = info->descriptionVersion;
|
||||
if (_version == version) {
|
||||
return false;
|
||||
}
|
||||
_version = version;
|
||||
_item = makeAboutBot(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
AdminLog::OwnedItem AboutView::makeAboutBot(not_null<BotInfo*> info) {
|
||||
const auto flags = MessageFlag::FakeAboutView
|
||||
| MessageFlag::FakeHistoryItem
|
||||
| MessageFlag::Local;
|
||||
const auto postAuthor = QString();
|
||||
const auto date = TimeId(0);
|
||||
const auto replyTo = FullReplyTo();
|
||||
const auto viaBotId = UserId(0);
|
||||
const auto groupedId = uint64(0);
|
||||
const auto textWithEntities = TextUtilities::ParseEntities(
|
||||
info->description,
|
||||
Ui::ItemTextBotNoMonoOptions().flags);
|
||||
const auto make = [&](auto &&a, auto &&b, auto &&...other) {
|
||||
return _history->makeMessage(
|
||||
_history->nextNonHistoryEntryId(),
|
||||
flags,
|
||||
replyTo,
|
||||
viaBotId,
|
||||
date,
|
||||
_history->peer->id,
|
||||
postAuthor,
|
||||
std::forward<decltype(a)>(a),
|
||||
std::forward<decltype(b)>(b),
|
||||
HistoryMessageMarkupData(),
|
||||
std::forward<decltype(other)>(other)...);
|
||||
};
|
||||
const auto item = info->document
|
||||
? make(info->document, textWithEntities)
|
||||
: info->photo
|
||||
? make(info->photo, textWithEntities)
|
||||
: make(textWithEntities, MTP_messageMediaEmpty(), groupedId);
|
||||
return AdminLog::OwnedItem(_delegate, item);
|
||||
}
|
||||
|
||||
AdminLog::OwnedItem AboutView::makePremiumRequired() {
|
||||
const auto flags = MessageFlag::FakeAboutView
|
||||
| MessageFlag::FakeHistoryItem
|
||||
| MessageFlag::Local;
|
||||
const auto date = TimeId(0);
|
||||
const auto item = _history->makeMessage(
|
||||
_history->nextNonHistoryEntryId(),
|
||||
flags,
|
||||
date,
|
||||
PreparedServiceText{ tr::lng_send_non_premium_text(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Bold(_history->peer->shortName()),
|
||||
Ui::Text::RichLangValue) },
|
||||
peerToUser(_history->peer->id));
|
||||
auto result = AdminLog::OwnedItem(_delegate, item);
|
||||
result->overrideMedia(std::make_unique<ServiceBox>(
|
||||
result.get(),
|
||||
std::make_unique<PremiumRequiredBox>(result.get())));
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
40
Telegram/SourceFiles/history/view/history_view_about_view.h
Normal file
40
Telegram/SourceFiles/history/view/history_view_about_view.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
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/admin_log/history_admin_log_item.h"
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
class AboutView final : public ClickHandlerHost {
|
||||
public:
|
||||
AboutView(
|
||||
not_null<History*> history,
|
||||
not_null<ElementDelegate*> delegate);
|
||||
|
||||
[[nodiscard]] not_null<History*> history() const;
|
||||
[[nodiscard]] Element *view() const;
|
||||
[[nodiscard]] HistoryItem *item() const;
|
||||
|
||||
bool refresh();
|
||||
|
||||
int top = 0;
|
||||
int height = 0;
|
||||
|
||||
private:
|
||||
[[nodiscard]] AdminLog::OwnedItem makeAboutBot(not_null<BotInfo*> info);
|
||||
[[nodiscard]] AdminLog::OwnedItem makePremiumRequired();
|
||||
|
||||
const not_null<History*> _history;
|
||||
const not_null<ElementDelegate*> _delegate;
|
||||
AdminLog::OwnedItem _item;
|
||||
int _version = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace HistoryView
|
|
@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_sponsored_messages.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
|
@ -472,8 +473,11 @@ Element::Element(
|
|||
if (_context == Context::History) {
|
||||
history()->setHasPendingResizedItems();
|
||||
}
|
||||
if (data->isFakeBotAbout() && !data->history()->peer->isRepliesChat()) {
|
||||
AddComponents(FakeBotAboutTop::Bit());
|
||||
if (data->isFakeAboutView()) {
|
||||
const auto user = data->history()->peer->asUser();
|
||||
if (user && user->isBot() && !user->isRepliesChat()) {
|
||||
AddComponents(FakeBotAboutTop::Bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -625,7 +625,7 @@ QSize Message::performCountOptimalSize() {
|
|||
refreshInfoSkipBlock();
|
||||
|
||||
const auto media = this->media();
|
||||
const auto botTop = item->isFakeBotAbout()
|
||||
const auto botTop = item->isFakeAboutView()
|
||||
? Get<FakeBotAboutTop>()
|
||||
: nullptr;
|
||||
if (botTop) {
|
||||
|
@ -3263,7 +3263,7 @@ bool Message::drawBubble() const {
|
|||
const auto item = data();
|
||||
if (isHidden()) {
|
||||
return false;
|
||||
} else if (logEntryOriginal() || item->isFakeBotAbout()) {
|
||||
} else if (logEntryOriginal() || item->isFakeAboutView()) {
|
||||
return true;
|
||||
}
|
||||
const auto media = this->media();
|
||||
|
@ -3760,7 +3760,7 @@ QRect Message::innerGeometry() const {
|
|||
|
||||
QRect Message::countGeometry() const {
|
||||
const auto item = data();
|
||||
const auto centeredView = item->isFakeBotAbout()
|
||||
const auto centeredView = item->isFakeAboutView()
|
||||
|| (context() == Context::Replies && item->isDiscussionPost());
|
||||
const auto media = this->media();
|
||||
const auto mediaWidth = (media && media->isDisplayed())
|
||||
|
@ -3822,7 +3822,7 @@ Ui::BubbleRounding Message::countMessageRounding() const {
|
|||
const auto skipTail = smallBottom
|
||||
|| (media && media->skipBubbleTail())
|
||||
|| (keyboard != nullptr)
|
||||
|| item->isFakeBotAbout()
|
||||
|| item->isFakeAboutView()
|
||||
|| (context() == Context::Replies && item->isDiscussionPost());
|
||||
const auto right = hasRightLayout();
|
||||
using Corner = Ui::BubbleCornerRounding;
|
||||
|
@ -3870,7 +3870,7 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
}
|
||||
|
||||
const auto item = data();
|
||||
const auto botTop = item->isFakeBotAbout()
|
||||
const auto botTop = item->isFakeAboutView()
|
||||
? Get<FakeBotAboutTop>()
|
||||
: nullptr;
|
||||
const auto media = this->media();
|
||||
|
@ -3878,7 +3878,7 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
const auto bubble = drawBubble();
|
||||
|
||||
// This code duplicates countGeometry() but also resizes media.
|
||||
const auto centeredView = item->isFakeBotAbout()
|
||||
const auto centeredView = item->isFakeAboutView()
|
||||
|| (context() == Context::Replies && item->isDiscussionPost());
|
||||
auto contentWidth = newWidth
|
||||
- st::msgMargin.left()
|
||||
|
|
|
@ -2045,7 +2045,7 @@ bool Gif::dataLoaded() const {
|
|||
}
|
||||
|
||||
bool Gif::needInfoDisplay() const {
|
||||
if (_parent->data()->isFakeBotAbout()) {
|
||||
if (_parent->data()->isFakeAboutView()) {
|
||||
return false;
|
||||
}
|
||||
return _parent->data()->isSending()
|
||||
|
|
|
@ -902,7 +902,7 @@ bool Photo::dataLoaded() const {
|
|||
}
|
||||
|
||||
bool Photo::needInfoDisplay() const {
|
||||
if (_parent->data()->isFakeBotAbout()) {
|
||||
if (_parent->data()->isFakeAboutView()) {
|
||||
return false;
|
||||
}
|
||||
return _parent->data()->isSending()
|
||||
|
|
|
@ -20,6 +20,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace HistoryView {
|
||||
|
||||
int ServiceBoxContent::width() {
|
||||
return st::msgServiceGiftBoxSize.width();
|
||||
}
|
||||
|
||||
ServiceBox::ServiceBox(
|
||||
not_null<Element*> parent,
|
||||
std::unique_ptr<ServiceBoxContent> content)
|
||||
|
@ -27,7 +31,7 @@ ServiceBox::ServiceBox(
|
|||
, _parent(parent)
|
||||
, _content(std::move(content))
|
||||
, _button({ .link = _content->createViewLink() })
|
||||
, _maxWidth(st::msgServiceGiftBoxSize.width()
|
||||
, _maxWidth(_content->width()
|
||||
- st::msgPadding.left()
|
||||
- st::msgPadding.right())
|
||||
, _title(
|
||||
|
@ -48,7 +52,7 @@ ServiceBox::ServiceBox(
|
|||
kMarkupTextOptions,
|
||||
_maxWidth)
|
||||
, _size(
|
||||
st::msgServiceGiftBoxSize.width(),
|
||||
_content->width(),
|
||||
(st::msgServiceGiftBoxTopSkip
|
||||
+ _content->top()
|
||||
+ _content->size().height()
|
||||
|
|
|
@ -19,6 +19,7 @@ class ServiceBoxContent {
|
|||
public:
|
||||
virtual ~ServiceBoxContent() = default;
|
||||
|
||||
[[nodiscard]] virtual int width();
|
||||
[[nodiscard]] virtual int top() = 0;
|
||||
[[nodiscard]] virtual QSize size() = 0;
|
||||
[[nodiscard]] virtual QString title() = 0;
|
||||
|
|
|
@ -965,6 +965,9 @@ historySendDisabled: FlatLabel(defaultFlatLabel) {
|
|||
historySendDisabledIcon: icon {{ "emoji/premium_lock", placeholderFgActive }};
|
||||
historySendDisabledIconSkip: 20px;
|
||||
historySendDisabledPosition: point(0px, 0px);
|
||||
historySendPremiumRequired: FlatLabel(historySendDisabled) {
|
||||
align: align(top);
|
||||
}
|
||||
|
||||
backgroundSwitchToDark: IconButton(defaultIconButton) {
|
||||
width: 48px;
|
||||
|
@ -1031,3 +1034,7 @@ chatSimilarName: TextStyle(defaultTextStyle) {
|
|||
}
|
||||
chatSimilarWidthMax: 424px;
|
||||
chatSimilarSkip: 12px;
|
||||
|
||||
premiumRequiredWidth: 186px;
|
||||
premiumRequiredIcon: icon{{ "chat/large_lockedchat", msgServiceFg }};
|
||||
premiumRequiredCircle: 60px;
|
||||
|
|
Loading…
Add table
Reference in a new issue