Show "premium required" information in chat.
This commit is contained in:
parent
c765bee0cd
commit
e5cda0e2b1
|
@ -752,6 +752,8 @@ PRIVATE
|
||||||
history/view/reactions/history_view_reactions_strip.h
|
history/view/reactions/history_view_reactions_strip.h
|
||||||
history/view/reactions/history_view_reactions_tabs.cpp
|
history/view/reactions/history_view_reactions_tabs.cpp
|
||||||
history/view/reactions/history_view_reactions_tabs.h
|
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.cpp
|
||||||
history/view/history_view_bottom_info.h
|
history/view/history_view_bottom_info.h
|
||||||
history/view/history_view_contact_status.cpp
|
history/view/history_view_contact_status.cpp
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
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_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_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_exceptions_list_title" = "Exceptions";
|
||||||
"lng_removed_list_title" = "Removed users";
|
"lng_removed_list_title" = "Removed users";
|
||||||
|
|
|
@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "settings/settings_premium.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
@ -904,3 +905,68 @@ base::unique_qptr<Ui::RpWidget> CreateDisabledFieldView(
|
||||||
});
|
});
|
||||||
return result;
|
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(
|
[[nodiscard]] base::unique_qptr<Ui::RpWidget> CreateDisabledFieldView(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<PeerData*> peer);
|
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_peer_values.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
#include "ui/chat/attach/attach_prepare.h"
|
#include "ui/chat/attach/attach_prepare.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -113,6 +114,9 @@ bool CanSendAnyOf(
|
||||||
if (const auto user = peer->asUser()) {
|
if (const auto user = peer->asUser()) {
|
||||||
if (user->isInaccessible() || user->isRepliesChat()) {
|
if (user->isInaccessible() || user->isRepliesChat()) {
|
||||||
return false;
|
return false;
|
||||||
|
} else if (user->meRequiresPremiumToWrite()
|
||||||
|
&& !user->session().premium()) {
|
||||||
|
return false;
|
||||||
} else if (rights
|
} else if (rights
|
||||||
& ~(ChatRestriction::SendVoiceMessages
|
& ~(ChatRestriction::SendVoiceMessages
|
||||||
| ChatRestriction::SendVideoMessages
|
| ChatRestriction::SendVideoMessages
|
||||||
|
@ -167,6 +171,13 @@ std::optional<QString> RestrictionError(
|
||||||
using Flag = ChatRestriction;
|
using Flag = ChatRestriction;
|
||||||
if (const auto restricted = peer->amRestricted(restriction)) {
|
if (const auto restricted = peer->amRestricted(restriction)) {
|
||||||
if (const auto user = peer->asUser()) {
|
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)
|
const auto result = (restriction == Flag::SendVoiceMessages)
|
||||||
? tr::lng_restricted_send_voice_messages(
|
? tr::lng_restricted_send_voice_messages(
|
||||||
tr::now,
|
tr::now,
|
||||||
|
|
|
@ -1101,6 +1101,9 @@ Data::RestrictionCheckResult PeerData::amRestricted(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (const auto user = asUser()) {
|
if (const auto user = asUser()) {
|
||||||
|
if (user->meRequiresPremiumToWrite() && !user->session().premium()) {
|
||||||
|
return Result::Explicit();
|
||||||
|
}
|
||||||
return (right == ChatRestriction::SendVoiceMessages
|
return (right == ChatRestriction::SendVoiceMessages
|
||||||
|| right == ChatRestriction::SendVideoMessages)
|
|| right == ChatRestriction::SendVideoMessages)
|
||||||
? ((user->flags() & UserDataFlag::VoiceMessagesForbidden)
|
? ((user->flags() & UserDataFlag::VoiceMessagesForbidden)
|
||||||
|
|
|
@ -217,13 +217,24 @@ inline auto DefaultRestrictionValue(
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
const auto other = rights & ~(ChatRestriction::SendVoiceMessages
|
const auto other = rights & ~(ChatRestriction::SendVoiceMessages
|
||||||
| ChatRestriction::SendVideoMessages);
|
| 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) {
|
if (other) {
|
||||||
return PeerFlagValue(user, UserDataFlag::Deleted)
|
return std::move(allowedAny);
|
||||||
| rpl::map(!_1);
|
|
||||||
}
|
}
|
||||||
const auto mask = UserDataFlag::Deleted
|
const auto mask = UserDataFlag::VoiceMessagesForbidden;
|
||||||
| UserDataFlag::VoiceMessagesForbidden;
|
return rpl::combine(
|
||||||
return PeerFlagsValue(user, mask) | rpl::map(!_1);
|
std::move(allowedAny),
|
||||||
|
PeerFlagValue(user, mask),
|
||||||
|
_1 && !_2);
|
||||||
} else if (const auto chat = peer->asChat()) {
|
} else if (const auto chat = peer->asChat()) {
|
||||||
const auto mask = ChatDataFlag()
|
const auto mask = ChatDataFlag()
|
||||||
| ChatDataFlag::Deactivated
|
| ChatDataFlag::Deactivated
|
||||||
|
|
|
@ -520,6 +520,7 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||||
| Flag::Premium
|
| Flag::Premium
|
||||||
| Flag::Support
|
| Flag::Support
|
||||||
| Flag::SomeRequirePremiumToWrite
|
| Flag::SomeRequirePremiumToWrite
|
||||||
|
| Flag::MeRequiresPremiumToWrite AssertIsDebug()
|
||||||
| Flag::RequirePremiumToWriteKnown
|
| Flag::RequirePremiumToWriteKnown
|
||||||
| (!minimal
|
| (!minimal
|
||||||
? Flag::Contact
|
? Flag::Contact
|
||||||
|
@ -542,7 +543,7 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||||
| (data.is_premium() ? Flag::Premium : Flag())
|
| (data.is_premium() ? Flag::Premium : Flag())
|
||||||
| (data.is_support() ? Flag::Support : Flag())
|
| (data.is_support() ? Flag::Support : Flag())
|
||||||
| (data.is_contact_require_premium()
|
| (data.is_contact_require_premium()
|
||||||
? (Flag::SomeRequirePremiumToWrite
|
? ((Flag::SomeRequirePremiumToWrite | Flag::MeRequiresPremiumToWrite) AssertIsDebug()
|
||||||
| (result->someRequirePremiumToWrite()
|
| (result->someRequirePremiumToWrite()
|
||||||
? (result->requirePremiumToWriteKnown()
|
? (result->requirePremiumToWriteKnown()
|
||||||
? Flag::RequirePremiumToWriteKnown
|
? Flag::RequirePremiumToWriteKnown
|
||||||
|
|
|
@ -300,8 +300,8 @@ enum class MessageFlag : uint64 {
|
||||||
OnlyEmojiAndSpaces = (1ULL << 35),
|
OnlyEmojiAndSpaces = (1ULL << 35),
|
||||||
OnlyEmojiAndSpacesSet = (1ULL << 36),
|
OnlyEmojiAndSpacesSet = (1ULL << 36),
|
||||||
|
|
||||||
// Fake message with bot cover and information.
|
// Fake message with some info, like bot cover and information.
|
||||||
FakeBotAbout = (1ULL << 37),
|
FakeAboutView = (1ULL << 37),
|
||||||
|
|
||||||
StoryItem = (1ULL << 38),
|
StoryItem = (1ULL << 38),
|
||||||
|
|
||||||
|
|
|
@ -506,7 +506,7 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
|
||||||
| Flag::VoiceMessagesForbidden
|
| Flag::VoiceMessagesForbidden
|
||||||
| Flag::ReadDatesPrivate
|
| Flag::ReadDatesPrivate
|
||||||
| Flag::RequirePremiumToWriteKnown
|
| Flag::RequirePremiumToWriteKnown
|
||||||
| Flag::MeRequiresPremiumToWrite;
|
/*| Flag::MeRequiresPremiumToWrite*/; AssertIsDebug()
|
||||||
user->setFlags((user->flags() & ~mask)
|
user->setFlags((user->flags() & ~mask)
|
||||||
| (update.is_phone_calls_private()
|
| (update.is_phone_calls_private()
|
||||||
? Flag::PhoneCallsPrivate
|
? Flag::PhoneCallsPrivate
|
||||||
|
|
|
@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "core/file_utilities.h"
|
#include "core/file_utilities.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
#include "history/admin_log/history_admin_log_item.h"
|
|
||||||
#include "history/history_item_helpers.h"
|
#include "history/history_item_helpers.h"
|
||||||
#include "history/view/controls/history_view_forward_panel.h"
|
#include "history/view/controls/history_view_forward_panel.h"
|
||||||
#include "history/view/controls/history_view_draft_options.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/media/history_view_web_page.h"
|
||||||
#include "history/view/reactions/history_view_reactions_button.h"
|
#include "history/view/reactions/history_view_reactions_button.h"
|
||||||
#include "history/view/reactions/history_view_reactions_selector.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_message.h"
|
||||||
#include "history/view/history_view_service_message.h"
|
#include "history/view/history_view_service_message.h"
|
||||||
#include "history/view/history_view_cursor_state.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(
|
HistoryInner::HistoryInner(
|
||||||
not_null<HistoryWidget*> historyWidget,
|
not_null<HistoryWidget*> historyWidget,
|
||||||
not_null<Ui::ScrollArea*> scroll,
|
not_null<Ui::ScrollArea*> scroll,
|
||||||
|
@ -447,7 +351,7 @@ HistoryInner::HistoryInner(
|
||||||
|
|
||||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||||
|
|
||||||
notifyIsBotChanged();
|
refreshAboutView();
|
||||||
|
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
_controller->gifPauseLevelChanged(
|
_controller->gifPauseLevelChanged(
|
||||||
|
@ -1011,10 +915,10 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
const auto historyDisplayedEmpty = _history->isDisplayedEmpty()
|
const auto historyDisplayedEmpty = _history->isDisplayedEmpty()
|
||||||
&& (!_migrated || _migrated->isDisplayedEmpty());
|
&& (!_migrated || _migrated->isDisplayedEmpty());
|
||||||
if (const auto view = _botAbout ? _botAbout->view() : nullptr) {
|
if (const auto view = _aboutView ? _aboutView->view() : nullptr) {
|
||||||
if (clip.y() < _botAbout->top + _botAbout->height
|
if (clip.y() < _aboutView->top + _aboutView->height
|
||||||
&& clip.y() + clip.height() > _botAbout->top) {
|
&& clip.y() + clip.height() > _aboutView->top) {
|
||||||
const auto top = _botAbout->top;
|
const auto top = _aboutView->top;
|
||||||
context.translate(0, -top);
|
context.translate(0, -top);
|
||||||
context.selection = computeRenderSelection(&_selected, view);
|
context.selection = computeRenderSelection(&_selected, view);
|
||||||
p.translate(0, top);
|
p.translate(0, top);
|
||||||
|
@ -3066,8 +2970,8 @@ void HistoryInner::recountHistoryGeometry() {
|
||||||
auto oldHistoryPaddingTop = qMax(
|
auto oldHistoryPaddingTop = qMax(
|
||||||
visibleHeight - historyHeight() - st::historyPaddingBottom,
|
visibleHeight - historyHeight() - st::historyPaddingBottom,
|
||||||
0);
|
0);
|
||||||
if (_botAbout) {
|
if (_aboutView) {
|
||||||
accumulate_max(oldHistoryPaddingTop, _botAbout->height);
|
accumulate_max(oldHistoryPaddingTop, _aboutView->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBotInfo(false);
|
updateBotInfo(false);
|
||||||
|
@ -3095,20 +2999,20 @@ void HistoryInner::recountHistoryGeometry() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto view = _botAbout ? _botAbout->view() : nullptr) {
|
if (const auto view = _aboutView ? _aboutView->view() : nullptr) {
|
||||||
_botAbout->height = view->resizeGetHeight(_contentWidth);
|
_aboutView->height = view->resizeGetHeight(_contentWidth);
|
||||||
_botAbout->top = qMin(
|
_aboutView->top = qMin(
|
||||||
_historyPaddingTop - _botAbout->height,
|
_historyPaddingTop - _aboutView->height,
|
||||||
qMax(0, (_scroll->height() - _botAbout->height) / 2));
|
qMax(0, (_scroll->height() - _aboutView->height) / 2));
|
||||||
} else if (_botAbout) {
|
} else if (_aboutView) {
|
||||||
_botAbout->top = _botAbout->height = 0;
|
_aboutView->top = _aboutView->height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newHistoryPaddingTop = qMax(
|
auto newHistoryPaddingTop = qMax(
|
||||||
visibleHeight - historyHeight() - st::historyPaddingBottom,
|
visibleHeight - historyHeight() - st::historyPaddingBottom,
|
||||||
0);
|
0);
|
||||||
if (_botAbout) {
|
if (_aboutView) {
|
||||||
accumulate_max(newHistoryPaddingTop, _botAbout->height);
|
accumulate_max(newHistoryPaddingTop, _aboutView->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto historyPaddingTopDelta = (newHistoryPaddingTop - oldHistoryPaddingTop);
|
auto historyPaddingTopDelta = (newHistoryPaddingTop - oldHistoryPaddingTop);
|
||||||
|
@ -3122,13 +3026,13 @@ void HistoryInner::recountHistoryGeometry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryInner::updateBotInfo(bool recount) {
|
void HistoryInner::updateBotInfo(bool recount) {
|
||||||
if (!_botAbout) {
|
if (!_aboutView) {
|
||||||
return;
|
return;
|
||||||
} else if (_botAbout->refresh() && recount && _contentWidth > 0) {
|
} else if (_aboutView->refresh() && recount && _contentWidth > 0) {
|
||||||
const auto view = _botAbout->view();
|
const auto view = _aboutView->view();
|
||||||
const auto now = view ? view->resizeGetHeight(_contentWidth) : 0;
|
const auto now = view ? view->resizeGetHeight(_contentWidth) : 0;
|
||||||
if (_botAbout->height != now) {
|
if (_aboutView->height != now) {
|
||||||
_botAbout->height = now;
|
_aboutView->height = now;
|
||||||
updateSize();
|
updateSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3276,14 +3180,14 @@ void HistoryInner::updateSize() {
|
||||||
const auto visibleHeight = _scroll->height();
|
const auto visibleHeight = _scroll->height();
|
||||||
const auto itemsHeight = historyHeight() - _revealHeight;
|
const auto itemsHeight = historyHeight() - _revealHeight;
|
||||||
auto newHistoryPaddingTop = qMax(visibleHeight - itemsHeight - st::historyPaddingBottom, 0);
|
auto newHistoryPaddingTop = qMax(visibleHeight - itemsHeight - st::historyPaddingBottom, 0);
|
||||||
if (_botAbout) {
|
if (_aboutView) {
|
||||||
accumulate_max(newHistoryPaddingTop, _botAbout->height);
|
accumulate_max(newHistoryPaddingTop, _aboutView->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_botAbout && _botAbout->height > 0) {
|
if (_aboutView && _aboutView->height > 0) {
|
||||||
_botAbout->top = qMin(
|
_aboutView->top = qMin(
|
||||||
newHistoryPaddingTop - _botAbout->height,
|
newHistoryPaddingTop - _aboutView->height,
|
||||||
qMax(0, (_scroll->height() - _botAbout->height) / 2));
|
qMax(0, (_scroll->height() - _aboutView->height) / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_historyPaddingTop != newHistoryPaddingTop) {
|
if (_historyPaddingTop != newHistoryPaddingTop) {
|
||||||
|
@ -3327,7 +3231,7 @@ void HistoryInner::leaveEventHook(QEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryInner::~HistoryInner() {
|
HistoryInner::~HistoryInner() {
|
||||||
_botAbout = nullptr;
|
_aboutView = nullptr;
|
||||||
for (const auto &item : _animatedStickersPlayed) {
|
for (const auto &item : _animatedStickersPlayed) {
|
||||||
if (const auto view = item->mainView()) {
|
if (const auto view = item->mainView()) {
|
||||||
if (const auto media = view->media()) {
|
if (const auto media = view->media()) {
|
||||||
|
@ -3641,11 +3545,11 @@ void HistoryInner::mouseActionUpdate() {
|
||||||
const auto reactionView = viewByItem(reactionItem);
|
const auto reactionView = viewByItem(reactionItem);
|
||||||
const auto view = reactionView
|
const auto view = reactionView
|
||||||
? reactionView
|
? reactionView
|
||||||
: (_botAbout
|
: (_aboutView
|
||||||
&& _botAbout->view()
|
&& _aboutView->view()
|
||||||
&& point.y() >= _botAbout->top
|
&& point.y() >= _aboutView->top
|
||||||
&& point.y() < _botAbout->top + _botAbout->view()->height())
|
&& point.y() < _aboutView->top + _aboutView->view()->height())
|
||||||
? _botAbout->view()
|
? _aboutView->view()
|
||||||
: (_curHistory && !_curHistory->isEmpty())
|
: (_curHistory && !_curHistory->isEmpty())
|
||||||
? _curHistory->blocks[_curBlock]->messages[_curItem].get()
|
? _curHistory->blocks[_curBlock]->messages[_curItem].get()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
@ -4004,8 +3908,8 @@ void HistoryInner::clearChooseReportReason() {
|
||||||
auto HistoryInner::viewByItem(const HistoryItem *item) const -> Element* {
|
auto HistoryInner::viewByItem(const HistoryItem *item) const -> Element* {
|
||||||
return !item
|
return !item
|
||||||
? nullptr
|
? nullptr
|
||||||
: (_botAbout && _botAbout->item() == item)
|
: (_aboutView && _aboutView->item() == item)
|
||||||
? _botAbout->view()
|
? _aboutView->view()
|
||||||
: item->mainView();
|
: item->mainView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4017,8 +3921,8 @@ int HistoryInner::itemTop(const HistoryItem *item) const {
|
||||||
int HistoryInner::itemTop(const Element *view) const {
|
int HistoryInner::itemTop(const Element *view) const {
|
||||||
if (!view) {
|
if (!view) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (_botAbout && view == _botAbout->view()) {
|
} else if (_aboutView && view == _aboutView->view()) {
|
||||||
return _botAbout->top;
|
return _aboutView->top;
|
||||||
} else if (view->data()->mainView() != view) {
|
} else if (view->data()->mainView() != view) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -4056,17 +3960,27 @@ auto HistoryInner::findViewForPinnedTracking(int top) const
|
||||||
return { nullptr, 0 };
|
return { nullptr, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryInner::notifyIsBotChanged() {
|
void HistoryInner::refreshAboutView() {
|
||||||
if (const auto user = _peer->asUser()) {
|
if (const auto user = _peer->asUser()) {
|
||||||
if (const auto info = user->botInfo.get()) {
|
if (const auto info = user->botInfo.get()) {
|
||||||
if (!_botAbout) {
|
if (!_aboutView) {
|
||||||
_botAbout = std::make_unique<BotAbout>(
|
_aboutView = std::make_unique<HistoryView::AboutView>(
|
||||||
_history,
|
_history,
|
||||||
_history->delegateMixin()->delegate());
|
_history->delegateMixin()->delegate());
|
||||||
}
|
}
|
||||||
if (!info->inited) {
|
if (!info->inited) {
|
||||||
session().api().requestFullPeer(_peer);
|
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) {
|
if (!toItems->empty() && toItems->cbegin()->second != FullSelection) {
|
||||||
toItems->clear();
|
toItems->clear();
|
||||||
}
|
}
|
||||||
const auto botAboutView = _botAbout ? _botAbout->view() : nullptr;
|
const auto botAboutView = _aboutView ? _aboutView->view() : nullptr;
|
||||||
if (_dragSelecting) {
|
if (_dragSelecting) {
|
||||||
auto fromblock = (_dragSelFrom != botAboutView)
|
auto fromblock = (_dragSelFrom != botAboutView)
|
||||||
? _dragSelFrom->block()->indexInHistory()
|
? _dragSelFrom->block()->indexInHistory()
|
||||||
|
|
|
@ -36,6 +36,7 @@ class Element;
|
||||||
class TranslateTracker;
|
class TranslateTracker;
|
||||||
struct PinnedId;
|
struct PinnedId;
|
||||||
struct SelectedQuote;
|
struct SelectedQuote;
|
||||||
|
class AboutView;
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
||||||
namespace HistoryView::Reactions {
|
namespace HistoryView::Reactions {
|
||||||
|
@ -192,7 +193,7 @@ public:
|
||||||
[[nodiscard]] std::pair<Element*, int> findViewForPinnedTracking(
|
[[nodiscard]] std::pair<Element*, int> findViewForPinnedTracking(
|
||||||
int top) const;
|
int top) const;
|
||||||
|
|
||||||
void notifyIsBotChanged();
|
void refreshAboutView();
|
||||||
void notifyMigrateUpdated();
|
void notifyMigrateUpdated();
|
||||||
|
|
||||||
// Ui::AbstractTooltipShower interface.
|
// Ui::AbstractTooltipShower interface.
|
||||||
|
@ -234,7 +235,6 @@ private:
|
||||||
void onTouchSelect();
|
void onTouchSelect();
|
||||||
void onTouchScrollTimer();
|
void onTouchScrollTimer();
|
||||||
|
|
||||||
class BotAbout;
|
|
||||||
using ChosenReaction = HistoryView::Reactions::ChosenReaction;
|
using ChosenReaction = HistoryView::Reactions::ChosenReaction;
|
||||||
using VideoUserpic = Dialogs::Ui::VideoUserpic;
|
using VideoUserpic = Dialogs::Ui::VideoUserpic;
|
||||||
using SelectedItems = std::map<HistoryItem*, TextSelection, std::less<>>;
|
using SelectedItems = std::map<HistoryItem*, TextSelection, std::less<>>;
|
||||||
|
@ -449,7 +449,7 @@ private:
|
||||||
// the first _history message date (just skip it by height).
|
// the first _history message date (just skip it by height).
|
||||||
int _historySkipHeight = 0;
|
int _historySkipHeight = 0;
|
||||||
|
|
||||||
std::unique_ptr<BotAbout> _botAbout;
|
std::unique_ptr<HistoryView::AboutView> _aboutView;
|
||||||
std::unique_ptr<HistoryView::EmptyPainter> _emptyPainter;
|
std::unique_ptr<HistoryView::EmptyPainter> _emptyPainter;
|
||||||
std::unique_ptr<HistoryView::TranslateTracker> _translateTracker;
|
std::unique_ptr<HistoryView::TranslateTracker> _translateTracker;
|
||||||
|
|
||||||
|
|
|
@ -314,8 +314,8 @@ public:
|
||||||
[[nodiscard]] bool isLocal() const {
|
[[nodiscard]] bool isLocal() const {
|
||||||
return _flags & MessageFlag::Local;
|
return _flags & MessageFlag::Local;
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool isFakeBotAbout() const {
|
[[nodiscard]] bool isFakeAboutView() const {
|
||||||
return _flags & MessageFlag::FakeBotAbout;
|
return _flags & MessageFlag::FakeAboutView;
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool showSimilarChannels() const {
|
[[nodiscard]] bool showSimilarChannels() const {
|
||||||
return _flags & MessageFlag::ShowSimilarChannels;
|
return _flags & MessageFlag::ShowSimilarChannels;
|
||||||
|
|
|
@ -577,7 +577,7 @@ HistoryWidget::HistoryWidget(
|
||||||
) | rpl::filter([=](not_null<UserData*> user) {
|
) | rpl::filter([=](not_null<UserData*> user) {
|
||||||
return (_peer == user.get());
|
return (_peer == user.get());
|
||||||
}) | rpl::start_with_next([=](not_null<UserData*> user) {
|
}) | rpl::start_with_next([=](not_null<UserData*> user) {
|
||||||
_list->notifyIsBotChanged();
|
_list->refreshAboutView();
|
||||||
_list->updateBotInfo();
|
_list->updateBotInfo();
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
|
@ -692,6 +692,17 @@ HistoryWidget::HistoryWidget(
|
||||||
scrollToCurrentVoiceMessage(pair.from.contextId(), pair.to);
|
scrollToCurrentVoiceMessage(pair.from.contextId(), pair.to);
|
||||||
}, lifetime());
|
}, 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;
|
using PeerUpdateFlag = Data::PeerUpdate::Flag;
|
||||||
session().changes().peerUpdates(
|
session().changes().peerUpdates(
|
||||||
PeerUpdateFlag::Rights
|
PeerUpdateFlag::Rights
|
||||||
|
@ -2728,18 +2739,6 @@ bool HistoryWidget::canWriteMessage() const {
|
||||||
return true;
|
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() {
|
void HistoryWidget::updateControlsVisibility() {
|
||||||
auto fieldDisabledRemoved = (_fieldDisabled != nullptr);
|
auto fieldDisabledRemoved = (_fieldDisabled != nullptr);
|
||||||
const auto guard = gsl::finally([&] {
|
const auto guard = gsl::finally([&] {
|
||||||
|
@ -2861,6 +2860,9 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
if (_inlineResults) {
|
if (_inlineResults) {
|
||||||
_inlineResults->hide();
|
_inlineResults->hide();
|
||||||
}
|
}
|
||||||
|
if (_sendRestriction) {
|
||||||
|
_sendRestriction->hide();
|
||||||
|
}
|
||||||
hideFieldIfVisible();
|
hideFieldIfVisible();
|
||||||
} else if (editingMessage() || _canSendMessages) {
|
} else if (editingMessage() || _canSendMessages) {
|
||||||
checkFieldAutocomplete();
|
checkFieldAutocomplete();
|
||||||
|
@ -2918,6 +2920,9 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
if (_botMenuButton) {
|
if (_botMenuButton) {
|
||||||
_botMenuButton->show();
|
_botMenuButton->show();
|
||||||
}
|
}
|
||||||
|
if (_sendRestriction) {
|
||||||
|
_sendRestriction->hide();
|
||||||
|
}
|
||||||
{
|
{
|
||||||
auto rightButtonsChanged = false;
|
auto rightButtonsChanged = false;
|
||||||
if (_silent) {
|
if (_silent) {
|
||||||
|
@ -3019,6 +3024,9 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
if (_inlineResults) {
|
if (_inlineResults) {
|
||||||
_inlineResults->hide();
|
_inlineResults->hide();
|
||||||
}
|
}
|
||||||
|
if (_sendRestriction) {
|
||||||
|
_sendRestriction->show();
|
||||||
|
}
|
||||||
_kbScroll->hide();
|
_kbScroll->hide();
|
||||||
hideFieldIfVisible();
|
hideFieldIfVisible();
|
||||||
}
|
}
|
||||||
|
@ -5131,6 +5139,9 @@ void HistoryWidget::moveFieldControls() {
|
||||||
_joinChannel->setGeometry(fullWidthButtonRect);
|
_joinChannel->setGeometry(fullWidthButtonRect);
|
||||||
_muteUnmute->setGeometry(fullWidthButtonRect);
|
_muteUnmute->setGeometry(fullWidthButtonRect);
|
||||||
_reportMessages->setGeometry(fullWidthButtonRect);
|
_reportMessages->setGeometry(fullWidthButtonRect);
|
||||||
|
if (_sendRestriction) {
|
||||||
|
_sendRestriction->setGeometry(fullWidthButtonRect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateFieldSize() {
|
void HistoryWidget::updateFieldSize() {
|
||||||
|
@ -5163,7 +5174,7 @@ void HistoryWidget::updateFieldSize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_fieldDisabled) {
|
if (_fieldDisabled) {
|
||||||
_fieldDisabled->resize(fieldWidth, fieldHeight());
|
_fieldDisabled->resize(width(), st::historySendSize.height());
|
||||||
}
|
}
|
||||||
if (_field->width() != fieldWidth) {
|
if (_field->width() != fieldWidth) {
|
||||||
_field->resize(fieldWidth, _field->height());
|
_field->resize(fieldWidth, _field->height());
|
||||||
|
@ -5849,6 +5860,46 @@ int HistoryWidget::countAutomaticScrollTop() {
|
||||||
return ScrollMax;
|
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(
|
void HistoryWidget::updateHistoryGeometry(
|
||||||
bool initial,
|
bool initial,
|
||||||
bool loadedDown,
|
bool loadedDown,
|
||||||
|
@ -5893,8 +5944,8 @@ void HistoryWidget::updateHistoryGeometry(
|
||||||
} else {
|
} else {
|
||||||
if (editingMessage() || _canSendMessages) {
|
if (editingMessage() || _canSendMessages) {
|
||||||
newScrollHeight -= (fieldHeight() + 2 * st::historySendPadding);
|
newScrollHeight -= (fieldHeight() + 2 * st::historySendPadding);
|
||||||
} else if (writeRestriction().has_value()) {
|
} else if (_sendRestriction) {
|
||||||
newScrollHeight -= _unblock->height();
|
newScrollHeight -= _sendRestriction->height();
|
||||||
}
|
}
|
||||||
if (_editMsgId
|
if (_editMsgId
|
||||||
|| replyTo()
|
|| replyTo()
|
||||||
|
@ -7605,6 +7656,7 @@ void HistoryWidget::fullInfoUpdated() {
|
||||||
|
|
||||||
void HistoryWidget::handlePeerUpdate() {
|
void HistoryWidget::handlePeerUpdate() {
|
||||||
bool resize = false;
|
bool resize = false;
|
||||||
|
updateSendRestriction();
|
||||||
updateHistoryGeometry();
|
updateHistoryGeometry();
|
||||||
if (_peer->isChat() && _peer->asChat()->noParticipantInfo()) {
|
if (_peer->isChat() && _peer->asChat()->noParticipantInfo()) {
|
||||||
session().api().requestFullPeer(_peer);
|
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 {
|
void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int top) const {
|
||||||
if (!rect.intersects(myrtlrect(left, top, width() - left, st::normalFont->height))) {
|
if (!rect.intersects(myrtlrect(left, top, width() - left, st::normalFont->height))) {
|
||||||
return;
|
return;
|
||||||
|
@ -8165,12 +8208,6 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
|
||||||
|| _kbShown) {
|
|| _kbShown) {
|
||||||
drawField(p, clip);
|
drawField(p, clip);
|
||||||
}
|
}
|
||||||
const auto error = restrictionHidden
|
|
||||||
? std::nullopt
|
|
||||||
: writeRestriction();
|
|
||||||
if (error) {
|
|
||||||
drawRestrictedWrite(p, *error);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const auto w = st::msgServiceFont->width(tr::lng_willbe_history(tr::now))
|
const auto w = st::msgServiceFont->width(tr::lng_willbe_history(tr::now))
|
||||||
+ st::msgPadding.left()
|
+ st::msgPadding.left()
|
||||||
|
|
|
@ -474,7 +474,6 @@ private:
|
||||||
[[nodiscard]] MsgId resolveReplyToTopicRootId();
|
[[nodiscard]] MsgId resolveReplyToTopicRootId();
|
||||||
[[nodiscard]] Data::ForumTopic *resolveReplyToTopic();
|
[[nodiscard]] Data::ForumTopic *resolveReplyToTopic();
|
||||||
[[nodiscard]] bool canWriteMessage() const;
|
[[nodiscard]] bool canWriteMessage() const;
|
||||||
std::optional<QString> writeRestriction() const;
|
|
||||||
void orderWidgets();
|
void orderWidgets();
|
||||||
|
|
||||||
[[nodiscard]] InlineBotQuery parseInlineBotQuery() const;
|
[[nodiscard]] InlineBotQuery parseInlineBotQuery() const;
|
||||||
|
@ -503,11 +502,8 @@ private:
|
||||||
bool editingMessage() const {
|
bool editingMessage() const {
|
||||||
return _editMsgId != 0;
|
return _editMsgId != 0;
|
||||||
}
|
}
|
||||||
bool jumpToDialogRow(const Dialogs::RowDescriptor &to);
|
|
||||||
|
|
||||||
void setupShortcuts();
|
void setupShortcuts();
|
||||||
bool showNextChat();
|
|
||||||
bool showPreviousChat();
|
|
||||||
|
|
||||||
void handlePeerMigration();
|
void handlePeerMigration();
|
||||||
|
|
||||||
|
@ -536,7 +532,6 @@ private:
|
||||||
const QRect &rect,
|
const QRect &rect,
|
||||||
int left,
|
int left,
|
||||||
int top) const;
|
int top) const;
|
||||||
void drawRestrictedWrite(Painter &p, const QString &error);
|
|
||||||
bool paintShowAnimationFrame();
|
bool paintShowAnimationFrame();
|
||||||
|
|
||||||
void updateMouseTracking();
|
void updateMouseTracking();
|
||||||
|
@ -559,6 +554,8 @@ private:
|
||||||
void addMessagesToFront(not_null<PeerData*> peer, const QVector<MTPMessage> &messages);
|
void addMessagesToFront(not_null<PeerData*> peer, const QVector<MTPMessage> &messages);
|
||||||
void addMessagesToBack(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 updateHistoryGeometry(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 });
|
||||||
void updateListSize();
|
void updateListSize();
|
||||||
void startItemRevealAnimations();
|
void startItemRevealAnimations();
|
||||||
|
@ -765,6 +762,8 @@ private:
|
||||||
bool _cmdStartShown = false;
|
bool _cmdStartShown = false;
|
||||||
object_ptr<Ui::InputField> _field;
|
object_ptr<Ui::InputField> _field;
|
||||||
base::unique_qptr<Ui::RpWidget> _fieldDisabled;
|
base::unique_qptr<Ui::RpWidget> _fieldDisabled;
|
||||||
|
base::unique_qptr<Ui::RpWidget> _sendRestriction;
|
||||||
|
QString _sendRestrictionKey;
|
||||||
Ui::Animations::Simple _inPhotoEditOver;
|
Ui::Animations::Simple _inPhotoEditOver;
|
||||||
bool _inDetails = false;
|
bool _inDetails = false;
|
||||||
bool _inPhotoEdit = false;
|
bool _inPhotoEdit = false;
|
||||||
|
|
|
@ -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
|
|
@ -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_forum_topic.h"
|
||||||
#include "data/data_sponsored_messages.h"
|
#include "data/data_sponsored_messages.h"
|
||||||
#include "data/data_message_reactions.h"
|
#include "data/data_message_reactions.h"
|
||||||
|
#include "data/data_user.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
|
||||||
|
@ -472,8 +473,11 @@ Element::Element(
|
||||||
if (_context == Context::History) {
|
if (_context == Context::History) {
|
||||||
history()->setHasPendingResizedItems();
|
history()->setHasPendingResizedItems();
|
||||||
}
|
}
|
||||||
if (data->isFakeBotAbout() && !data->history()->peer->isRepliesChat()) {
|
if (data->isFakeAboutView()) {
|
||||||
AddComponents(FakeBotAboutTop::Bit());
|
const auto user = data->history()->peer->asUser();
|
||||||
|
if (user && user->isBot() && !user->isRepliesChat()) {
|
||||||
|
AddComponents(FakeBotAboutTop::Bit());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -625,7 +625,7 @@ QSize Message::performCountOptimalSize() {
|
||||||
refreshInfoSkipBlock();
|
refreshInfoSkipBlock();
|
||||||
|
|
||||||
const auto media = this->media();
|
const auto media = this->media();
|
||||||
const auto botTop = item->isFakeBotAbout()
|
const auto botTop = item->isFakeAboutView()
|
||||||
? Get<FakeBotAboutTop>()
|
? Get<FakeBotAboutTop>()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
if (botTop) {
|
if (botTop) {
|
||||||
|
@ -3263,7 +3263,7 @@ bool Message::drawBubble() const {
|
||||||
const auto item = data();
|
const auto item = data();
|
||||||
if (isHidden()) {
|
if (isHidden()) {
|
||||||
return false;
|
return false;
|
||||||
} else if (logEntryOriginal() || item->isFakeBotAbout()) {
|
} else if (logEntryOriginal() || item->isFakeAboutView()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const auto media = this->media();
|
const auto media = this->media();
|
||||||
|
@ -3760,7 +3760,7 @@ QRect Message::innerGeometry() const {
|
||||||
|
|
||||||
QRect Message::countGeometry() const {
|
QRect Message::countGeometry() const {
|
||||||
const auto item = data();
|
const auto item = data();
|
||||||
const auto centeredView = item->isFakeBotAbout()
|
const auto centeredView = item->isFakeAboutView()
|
||||||
|| (context() == Context::Replies && item->isDiscussionPost());
|
|| (context() == Context::Replies && item->isDiscussionPost());
|
||||||
const auto media = this->media();
|
const auto media = this->media();
|
||||||
const auto mediaWidth = (media && media->isDisplayed())
|
const auto mediaWidth = (media && media->isDisplayed())
|
||||||
|
@ -3822,7 +3822,7 @@ Ui::BubbleRounding Message::countMessageRounding() const {
|
||||||
const auto skipTail = smallBottom
|
const auto skipTail = smallBottom
|
||||||
|| (media && media->skipBubbleTail())
|
|| (media && media->skipBubbleTail())
|
||||||
|| (keyboard != nullptr)
|
|| (keyboard != nullptr)
|
||||||
|| item->isFakeBotAbout()
|
|| item->isFakeAboutView()
|
||||||
|| (context() == Context::Replies && item->isDiscussionPost());
|
|| (context() == Context::Replies && item->isDiscussionPost());
|
||||||
const auto right = hasRightLayout();
|
const auto right = hasRightLayout();
|
||||||
using Corner = Ui::BubbleCornerRounding;
|
using Corner = Ui::BubbleCornerRounding;
|
||||||
|
@ -3870,7 +3870,7 @@ int Message::resizeContentGetHeight(int newWidth) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto item = data();
|
const auto item = data();
|
||||||
const auto botTop = item->isFakeBotAbout()
|
const auto botTop = item->isFakeAboutView()
|
||||||
? Get<FakeBotAboutTop>()
|
? Get<FakeBotAboutTop>()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto media = this->media();
|
const auto media = this->media();
|
||||||
|
@ -3878,7 +3878,7 @@ int Message::resizeContentGetHeight(int newWidth) {
|
||||||
const auto bubble = drawBubble();
|
const auto bubble = drawBubble();
|
||||||
|
|
||||||
// This code duplicates countGeometry() but also resizes media.
|
// This code duplicates countGeometry() but also resizes media.
|
||||||
const auto centeredView = item->isFakeBotAbout()
|
const auto centeredView = item->isFakeAboutView()
|
||||||
|| (context() == Context::Replies && item->isDiscussionPost());
|
|| (context() == Context::Replies && item->isDiscussionPost());
|
||||||
auto contentWidth = newWidth
|
auto contentWidth = newWidth
|
||||||
- st::msgMargin.left()
|
- st::msgMargin.left()
|
||||||
|
|
|
@ -2045,7 +2045,7 @@ bool Gif::dataLoaded() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Gif::needInfoDisplay() const {
|
bool Gif::needInfoDisplay() const {
|
||||||
if (_parent->data()->isFakeBotAbout()) {
|
if (_parent->data()->isFakeAboutView()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _parent->data()->isSending()
|
return _parent->data()->isSending()
|
||||||
|
|
|
@ -902,7 +902,7 @@ bool Photo::dataLoaded() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Photo::needInfoDisplay() const {
|
bool Photo::needInfoDisplay() const {
|
||||||
if (_parent->data()->isFakeBotAbout()) {
|
if (_parent->data()->isFakeAboutView()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _parent->data()->isSending()
|
return _parent->data()->isSending()
|
||||||
|
|
|
@ -20,6 +20,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
|
||||||
|
int ServiceBoxContent::width() {
|
||||||
|
return st::msgServiceGiftBoxSize.width();
|
||||||
|
}
|
||||||
|
|
||||||
ServiceBox::ServiceBox(
|
ServiceBox::ServiceBox(
|
||||||
not_null<Element*> parent,
|
not_null<Element*> parent,
|
||||||
std::unique_ptr<ServiceBoxContent> content)
|
std::unique_ptr<ServiceBoxContent> content)
|
||||||
|
@ -27,7 +31,7 @@ ServiceBox::ServiceBox(
|
||||||
, _parent(parent)
|
, _parent(parent)
|
||||||
, _content(std::move(content))
|
, _content(std::move(content))
|
||||||
, _button({ .link = _content->createViewLink() })
|
, _button({ .link = _content->createViewLink() })
|
||||||
, _maxWidth(st::msgServiceGiftBoxSize.width()
|
, _maxWidth(_content->width()
|
||||||
- st::msgPadding.left()
|
- st::msgPadding.left()
|
||||||
- st::msgPadding.right())
|
- st::msgPadding.right())
|
||||||
, _title(
|
, _title(
|
||||||
|
@ -48,7 +52,7 @@ ServiceBox::ServiceBox(
|
||||||
kMarkupTextOptions,
|
kMarkupTextOptions,
|
||||||
_maxWidth)
|
_maxWidth)
|
||||||
, _size(
|
, _size(
|
||||||
st::msgServiceGiftBoxSize.width(),
|
_content->width(),
|
||||||
(st::msgServiceGiftBoxTopSkip
|
(st::msgServiceGiftBoxTopSkip
|
||||||
+ _content->top()
|
+ _content->top()
|
||||||
+ _content->size().height()
|
+ _content->size().height()
|
||||||
|
|
|
@ -19,6 +19,7 @@ class ServiceBoxContent {
|
||||||
public:
|
public:
|
||||||
virtual ~ServiceBoxContent() = default;
|
virtual ~ServiceBoxContent() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual int width();
|
||||||
[[nodiscard]] virtual int top() = 0;
|
[[nodiscard]] virtual int top() = 0;
|
||||||
[[nodiscard]] virtual QSize size() = 0;
|
[[nodiscard]] virtual QSize size() = 0;
|
||||||
[[nodiscard]] virtual QString title() = 0;
|
[[nodiscard]] virtual QString title() = 0;
|
||||||
|
|
|
@ -965,6 +965,9 @@ historySendDisabled: FlatLabel(defaultFlatLabel) {
|
||||||
historySendDisabledIcon: icon {{ "emoji/premium_lock", placeholderFgActive }};
|
historySendDisabledIcon: icon {{ "emoji/premium_lock", placeholderFgActive }};
|
||||||
historySendDisabledIconSkip: 20px;
|
historySendDisabledIconSkip: 20px;
|
||||||
historySendDisabledPosition: point(0px, 0px);
|
historySendDisabledPosition: point(0px, 0px);
|
||||||
|
historySendPremiumRequired: FlatLabel(historySendDisabled) {
|
||||||
|
align: align(top);
|
||||||
|
}
|
||||||
|
|
||||||
backgroundSwitchToDark: IconButton(defaultIconButton) {
|
backgroundSwitchToDark: IconButton(defaultIconButton) {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
|
@ -1031,3 +1034,7 @@ chatSimilarName: TextStyle(defaultTextStyle) {
|
||||||
}
|
}
|
||||||
chatSimilarWidthMax: 424px;
|
chatSimilarWidthMax: 424px;
|
||||||
chatSimilarSkip: 12px;
|
chatSimilarSkip: 12px;
|
||||||
|
|
||||||
|
premiumRequiredWidth: 186px;
|
||||||
|
premiumRequiredIcon: icon{{ "chat/large_lockedchat", msgServiceFg }};
|
||||||
|
premiumRequiredCircle: 60px;
|
||||||
|
|
Loading…
Reference in New Issue