Support PeerData::isVerifyCodes() peer type.

This commit is contained in:
John Preston 2024-09-20 17:29:30 +04:00
parent 4803bd4b3f
commit 79b1c0edee
47 changed files with 391 additions and 85 deletions

View file

@ -3273,6 +3273,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_replies_discussion_started" = "Discussion started";
"lng_replies_no_comments" = "No comments here yet...";
"lng_verification_codes" = "Verification Codes";
"lng_archived_name" = "Archived chats";
"lng_archived_add" = "Archive";
"lng_archived_remove" = "Unarchive";

View file

@ -356,11 +356,12 @@ void PrivacyExceptionsBoxController::rowClicked(not_null<PeerListRow*> row) {
auto PrivacyExceptionsBoxController::createRow(not_null<History*> history)
-> std::unique_ptr<Row> {
if (history->peer->isSelf() || history->peer->isRepliesChat()) {
const auto peer = history->peer;
if (peer->isSelf() || peer->isRepliesChat() || peer->isVerifyCodes()) {
return nullptr;
} else if (!history->peer->isUser()
&& !history->peer->isChat()
&& !history->peer->isMegagroup()) {
} else if (!peer->isUser()
&& !peer->isChat()
&& !peer->isMegagroup()) {
return nullptr;
}
auto result = std::make_unique<Row>(history);

View file

@ -131,10 +131,13 @@ ExceptionRow::ExceptionRow(not_null<History*> history) : Row(history) {
}
QString ExceptionRow::generateName() {
return peer()->isSelf()
const auto peer = this->peer();
return peer->isSelf()
? tr::lng_saved_messages(tr::now)
: peer()->isRepliesChat()
: peer->isRepliesChat()
? tr::lng_replies_messages(tr::now)
: peer->isVerifyCodes()
? tr::lng_verification_codes(tr::now)
: Row::generateName();
}
@ -147,15 +150,19 @@ PaintRoundImageCallback ExceptionRow::generatePaintUserpicCallback(
const auto peer = this->peer();
const auto saved = peer->isSelf();
const auto replies = peer->isRepliesChat();
const auto verifyCodes = peer->isVerifyCodes();
auto userpic = saved ? Ui::PeerUserpicView() : ensureUserpicView();
if (forceRound && peer->isForum()) {
return ForceRoundUserpicCallback(peer);
}
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
using namespace Ui;
if (saved) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
} else if (replies) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
} else if (verifyCodes) {
EmptyUserpic::PaintVerifyCodes(p, x, y, outerWidth, size);
} else {
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
}

View file

@ -122,9 +122,11 @@ void FilterChatsPreview::paintEvent(QPaintEvent *e) {
top += st.height;
}
for (auto &[history, userpic, name, button] : _removePeer) {
const auto savedMessages = history->peer->isSelf();
const auto repliesMessages = history->peer->isRepliesChat();
if (savedMessages || repliesMessages) {
const auto peer = history->peer;
const auto savedMessages = peer->isSelf();
const auto repliesMessages = peer->isRepliesChat();
const auto verifyCodes = peer->isVerifyCodes();
if (savedMessages || repliesMessages || verifyCodes) {
if (savedMessages) {
Ui::EmptyUserpic::PaintSavedMessages(
p,
@ -132,13 +134,20 @@ void FilterChatsPreview::paintEvent(QPaintEvent *e) {
top + iconTop,
width(),
st.photoSize);
} else {
} else if (repliesMessages) {
Ui::EmptyUserpic::PaintRepliesMessages(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
} else {
Ui::EmptyUserpic::PaintVerifyCodes(
p,
iconLeft,
top + iconTop,
width(),
st.photoSize);
}
p.setPen(st::contactsNameFg);
p.drawTextLeft(
@ -147,7 +156,9 @@ void FilterChatsPreview::paintEvent(QPaintEvent *e) {
width(),
(savedMessages
? tr::lng_saved_messages(tr::now)
: tr::lng_replies_messages(tr::now)));
: repliesMessages
? tr::lng_replies_messages(tr::now)
: tr::lng_verification_codes(tr::now)));
} else {
history->peer->paintUserpicLeft(
p,

View file

@ -328,6 +328,7 @@ PaintRoundImageCallback ChatRow::generatePaintUserpicCallback(
const auto peer = this->peer();
const auto saved = peer->isSelf();
const auto replies = peer->isRepliesChat();
const auto verifyCodes = peer->isVerifyCodes();
auto userpic = (saved || replies)
? Ui::PeerUserpicView()
: ensureUserpicView();
@ -337,12 +338,15 @@ PaintRoundImageCallback ChatRow::generatePaintUserpicCallback(
int y,
int outerWidth,
int size) mutable {
using namespace Ui;
if (forceRound && peer->isForum()) {
ForceRoundUserpicCallback(peer)(p, x, y, outerWidth, size);
} else if (saved) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
} else if (replies) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
} else if (verifyCodes) {
EmptyUserpic::PaintVerifyCodes(p, x, y, outerWidth, size);
} else {
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
}

View file

@ -55,6 +55,10 @@ PaintRoundImageCallback PaintUserpicCallback(
return [](QPainter &p, int x, int y, int outerWidth, int size) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
};
} else if (peer->isVerifyCodes()) {
return [](QPainter &p, int x, int y, int outerWidth, int size) {
Ui::EmptyUserpic::PaintVerifyCodes(p, x, y, outerWidth, size);
};
}
}
auto userpic = Ui::PeerUserpicView();
@ -447,6 +451,8 @@ void PeerListBox::addSelectItem(
? tr::lng_saved_short(tr::now)
: (respect && peer->isRepliesChat())
? tr::lng_replies_messages(tr::now)
: (respect && peer->isVerifyCodes())
? tr::lng_verification_codes(tr::now)
: peer->shortName();
addSelectItem(
peer->id.value,
@ -625,6 +631,8 @@ void PeerListRow::refreshName(const style::PeerListItem &st) {
? tr::lng_saved_messages(tr::now)
: _isRepliesMessagesChat
? tr::lng_replies_messages(tr::now)
: _isVerifyCodesChat
? tr::lng_verification_codes(tr::now)
: generateName();
_name.setText(st.nameStyle, text, Ui::NameTextOptions());
}
@ -695,6 +703,8 @@ QString PeerListRow::generateShortName() {
? tr::lng_saved_short(tr::now)
: _isRepliesMessagesChat
? tr::lng_replies_messages(tr::now)
: _isVerifyCodesChat
? tr::lng_verification_codes(tr::now)
: peer()->shortName();
}
@ -709,16 +719,20 @@ PaintRoundImageCallback PeerListRow::generatePaintUserpicCallback(
bool forceRound) {
const auto saved = !_savedMessagesStatus.isEmpty();
const auto replies = _isRepliesMessagesChat;
const auto verifyCodes = _isVerifyCodesChat;
const auto peer = this->peer();
auto userpic = saved ? Ui::PeerUserpicView() : ensureUserpicView();
if (forceRound && peer->isForum()) {
return ForceRoundUserpicCallback(peer);
}
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
using namespace Ui;
if (saved) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
} else if (replies) {
Ui::EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
EmptyUserpic::PaintRepliesMessages(p, x, y, outerWidth, size);
} else if (verifyCodes) {
EmptyUserpic::PaintVerifyCodes(p, x, y, outerWidth, size);
} else {
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
}
@ -759,7 +773,8 @@ int PeerListRow::paintNameIconGetWidth(
bool selected) {
if (special()
|| !_savedMessagesStatus.isEmpty()
|| _isRepliesMessagesChat) {
|| _isRepliesMessagesChat
|| _isVerifyCodesChat) {
return 0;
}
return _bagde.drawGetWidth(
@ -874,12 +889,15 @@ void PeerListRow::paintDisabledCheckUserpic(
auto iconBorderPen = st.checkbox.check.border->p;
iconBorderPen.setWidth(st.checkbox.selectWidth);
const auto size = userpicRadius * 2;
if (!_savedMessagesStatus.isEmpty()) {
Ui::EmptyUserpic::PaintSavedMessages(p, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
Ui::EmptyUserpic::PaintSavedMessages(p, userpicLeft, userpicTop, outerWidth, size);
} else if (_isRepliesMessagesChat) {
Ui::EmptyUserpic::PaintRepliesMessages(p, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
Ui::EmptyUserpic::PaintRepliesMessages(p, userpicLeft, userpicTop, outerWidth, size);
} else if (_isVerifyCodesChat) {
Ui::EmptyUserpic::PaintVerifyCodes(p, userpicLeft, userpicTop, outerWidth, size);
} else {
peer()->paintUserpicLeft(p, _userpic, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
peer()->paintUserpicLeft(p, _userpic, userpicLeft, userpicTop, outerWidth, size);
}
{
@ -1069,10 +1087,13 @@ void PeerListContent::setRowHidden(not_null<PeerListRow*> row, bool hidden) {
void PeerListContent::addRowEntry(not_null<PeerListRow*> row) {
const auto savedMessagesStatus = _controller->savedMessagesChatStatus();
if (!savedMessagesStatus.isEmpty() && !row->special()) {
if (row->peer()->isSelf()) {
const auto peer = row->peer();
if (peer->isSelf()) {
row->setSavedMessagesChatStatus(savedMessagesStatus);
} else if (row->peer()->isRepliesChat()) {
} else if (peer->isRepliesChat()) {
row->setIsRepliesMessagesChat(true);
} else if (peer->isVerifyCodes()) {
row->setIsVerifyCodesChat(true);
}
}
_rowsById.emplace(row->id(), row);

View file

@ -200,6 +200,9 @@ public:
void setIsRepliesMessagesChat(bool isRepliesMessagesChat) {
_isRepliesMessagesChat = isRepliesMessagesChat;
}
void setIsVerifyCodesChat(bool isVerifyCodesChat) {
_isVerifyCodesChat = isVerifyCodesChat;
}
template <typename UpdateCallback>
void setChecked(
@ -299,6 +302,7 @@ private:
bool _initialized : 1 = false;
bool _isSearchResult : 1 = false;
bool _isRepliesMessagesChat : 1 = false;
bool _isVerifyCodesChat : 1 = false;
};

View file

@ -842,6 +842,7 @@ auto ChooseRecipientBoxController::createRow(
? !_filter(history)
: ((peer->isBroadcast() && !Data::CanSendAnything(peer))
|| peer->isRepliesChat()
|| peer->isVerifyCodes()
|| (peer->isUser() && (_premiumRequiredError
? !peer->asUser()->canSendIgnoreRequirePremium()
: !Data::CanSendAnything(peer))));

View file

@ -269,7 +269,8 @@ PaintRoundImageCallback ForbiddenRow::generatePaintUserpicCallback(
const auto peer = this->peer();
const auto saved = peer->isSelf();
const auto replies = peer->isRepliesChat();
auto userpic = (saved || replies)
const auto verifyCodes = peer->isVerifyCodes();
auto userpic = (saved || replies || verifyCodes)
? Ui::PeerUserpicView()
: ensureUserpicView();
auto paint = [=](
@ -302,6 +303,7 @@ PaintRoundImageCallback ForbiddenRow::generatePaintUserpicCallback(
repaint = (_paletteVersion != style::PaletteVersion())
|| (!saved
&& !replies
&& !verifyCodes
&& (_userpicKey != peer->userpicUniqueKey(userpic)));
}
if (repaint) {

View file

@ -838,6 +838,8 @@ void ShareBox::Inner::updateChatName(not_null<Chat*> chat) {
? tr::lng_saved_messages(tr::now)
: peer->isRepliesChat()
? tr::lng_replies_messages(tr::now)
: peer->isVerifyCodes()
? tr::lng_verification_codes(tr::now)
: peer->name();
chat->name.setText(_st.item.nameStyle, text, Ui::NameTextOptions());
}

View file

@ -367,17 +367,6 @@ void MonospaceClickHandler::onClick(ClickContext context) const {
}
const auto my = context.other.value<ClickHandlerContext>();
if (const auto controller = my.sessionWindow.get()) {
auto &data = controller->session().data();
const auto item = data.message(my.itemId);
const auto hasCopyRestriction = item
&& (!item->history()->peer->allowsForwarding()
|| item->forbidsForward());
if (hasCopyRestriction) {
controller->showToast(item->history()->peer->isBroadcast()
? tr::lng_error_nocopy_channel(tr::now)
: tr::lng_error_nocopy_group(tr::now));
return;
}
controller->showToast(tr::lng_text_copied(tr::now));
}
TextUtilities::SetClipboardText(TextForMimeData::Simple(_text.trimmed()));

View file

@ -112,7 +112,9 @@ bool CanSendAnyOf(
ChatRestrictions rights,
bool forbidInForums) {
if (const auto user = peer->asUser()) {
if (user->isInaccessible() || user->isRepliesChat()) {
if (user->isInaccessible()
|| user->isRepliesChat()
|| user->isVerifyCodes()) {
return false;
} else if (user->meRequiresPremiumToWrite()
&& !user->session().premium()) {

View file

@ -628,7 +628,8 @@ bool PeerData::canCreatePolls() const {
if (const auto user = asUser()) {
return user->isBot()
&& !user->isSupport()
&& !user->isRepliesChat();
&& !user->isRepliesChat()
&& !user->isVerifyCodes();
}
return Data::CanSend(this, ChatRestriction::SendPolls);
}
@ -664,7 +665,7 @@ bool PeerData::canEditMessagesIndefinitely() const {
}
bool PeerData::canExportChatHistory() const {
if (isRepliesChat() || !allowsForwarding()) {
if (isRepliesChat() || isVerifyCodes() || !allowsForwarding()) {
return false;
} else if (const auto channel = asChannel()) {
if (!channel->amIn() && channel->invitePeekExpires()) {
@ -865,6 +866,13 @@ void PeerData::fillNames() {
if (localized != english) {
appendToIndex(localized);
}
} else if (isVerifyCodes()) {
const auto english = u"Verification Codes"_q;
const auto localized = tr::lng_verification_codes(tr::now);
appendToIndex(english);
if (localized != english) {
appendToIndex(localized);
}
}
} else if (const auto channel = asChannel()) {
appendToIndex(channel->username());
@ -1202,8 +1210,13 @@ bool PeerData::isRepliesChat() const {
: kTestId) == id;
}
bool PeerData::isVerifyCodes() const {
constexpr auto kVerifyCodesId = peerFromUser(489000);
return (id == kVerifyCodesId);
}
bool PeerData::sharedMediaInfo() const {
return isSelf() || isRepliesChat();
return isSelf() || isRepliesChat() || isVerifyCodes();
}
bool PeerData::savedSublistsInfo() const {

View file

@ -227,6 +227,7 @@ public:
[[nodiscard]] bool isForum() const;
[[nodiscard]] bool isGigagroup() const;
[[nodiscard]] bool isRepliesChat() const;
[[nodiscard]] bool isVerifyCodes() const;
[[nodiscard]] bool sharedMediaInfo() const;
[[nodiscard]] bool savedSublistsInfo() const;
[[nodiscard]] bool hasStoriesHidden() const;

View file

@ -216,7 +216,7 @@ inline auto DefaultRestrictionValue(
ChatRestrictions rights,
bool forbidInForums) {
if (const auto user = peer->asUser()) {
if (user->isRepliesChat()) {
if (user->isRepliesChat() || user->isVerifyCodes()) {
return rpl::single(false);
}
using namespace rpl::mappers;

View file

@ -452,7 +452,7 @@ bool UserData::requirePremiumToWriteKnown() const {
}
bool UserData::canSendIgnoreRequirePremium() const {
return !isInaccessible() && !isRepliesChat();
return !isInaccessible() && !isRepliesChat() && !isVerifyCodes();
}
bool UserData::readDatesPrivate() const {

View file

@ -604,6 +604,8 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::userpic(
image = Ui::MakeSavedMessagesThumbnail();
} else if (v[0] == u"replies"_q) {
image = Ui::MakeRepliesThumbnail();
} else if (v[0] == u"verify_codes"_q) {
image = Ui::MakeVerifyCodesThumbnail();
} else {
const auto id = PeerId(v[0].toULongLong());
image = Ui::MakeUserpicThumbnail(_owner->peer(id));
@ -1017,6 +1019,8 @@ QString CustomEmojiManager::registerInternalEmoji(
? u"self"_q
: peer->isRepliesChat()
? u"replies"_q
: peer->isVerifyCodes()
? u"verify_codes"_q
: QString::number(peer->id.value);
return UserpicEmojiPrefix() + id + InternalPadding(padding);
}

View file

@ -355,6 +355,7 @@ dialogsForumIcon: ThreeStateIcon {
}
dialogsArchiveUserpic: icon {{ "archive_userpic", historyPeerUserpicFg }};
dialogsRepliesUserpic: icon {{ "replies_userpic", historyPeerUserpicFg }};
dialogsVerifyCodesUserpic: icon {{ "replies_userpic", historyPeerUserpicFg }};
dialogsInaccessibleUserpic: icon {{ "dialogs/inaccessible_userpic", historyPeerUserpicFg }};
dialogsHiddenAuthorUserpic: icon {{ "dialogs/avatar_hidden", premiumButtonFg }};
dialogsMyNotesUserpic: icon {{ "dialogs/avatar_notes", historyPeerUserpicFg }};

View file

@ -49,7 +49,10 @@ namespace {
const auto kPsaBadgePrefix = "cloud_lng_badge_psa_";
[[nodiscard]] bool ShowUserBotIcon(not_null<UserData*> user) {
return user->isBot() && !user->isSupport() && !user->isRepliesChat();
return user->isBot()
&& !user->isSupport()
&& !user->isRepliesChat()
&& !user->isVerifyCodes();
}
[[nodiscard]] bool ShowSendActionInDialogs(Data::Thread *thread) {
@ -245,10 +248,11 @@ void PaintFolderEntryText(
enum class Flag {
SavedMessages = 0x008,
RepliesMessages = 0x010,
AllowUserOnline = 0x020,
TopicJumpRipple = 0x040,
HiddenAuthor = 0x080,
MyNotes = 0x100,
VerifyCodes = 0x020,
AllowUserOnline = 0x040,
TopicJumpRipple = 0x080,
HiddenAuthor = 0x100,
MyNotes = 0x200,
};
inline constexpr bool is_flag_type(Flag) { return true; }
@ -307,6 +311,13 @@ void PaintRow(
context.st->padding.top(),
context.width,
context.st->photoSize);
} else if (flags & Flag::VerifyCodes) {
EmptyUserpic::PaintVerifyCodes(
p,
context.st->padding.left(),
context.st->padding.top(),
context.width,
context.st->photoSize);
} else if (flags & Flag::HiddenAuthor) {
EmptyUserpic::PaintHiddenAuthor(
p,
@ -615,12 +626,15 @@ void PaintRow(
if (flags
& (Flag::SavedMessages
| Flag::RepliesMessages
| Flag::VerifyCodes
| Flag::HiddenAuthor
| Flag::MyNotes)) {
auto text = (flags & Flag::SavedMessages)
? tr::lng_saved_messages(tr::now)
: (flags & Flag::RepliesMessages)
? tr::lng_replies_messages(tr::now)
: (flags & Flag::VerifyCodes)
? tr::lng_verification_codes(tr::now)
: (flags & Flag::MyNotes)
? tr::lng_my_notes(tr::now)
: tr::lng_hidden_author_messages(tr::now);
@ -806,6 +820,9 @@ void RowPainter::Paint(
| ((from && from->isRepliesChat())
? Flag::RepliesMessages
: Flag(0))
| ((from && from->isVerifyCodes())
? Flag::VerifyCodes
: Flag(0))
| ((sublist && from->isSavedHiddenAuthor())
? Flag::HiddenAuthor
: Flag(0))
@ -962,8 +979,12 @@ void RowPainter::Paint(
const auto showRepliesMessages = history
&& history->peer->isRepliesChat()
&& !row->searchInChat();
const auto showVerifyCodes = history
&& history->peer->isVerifyCodes()
&& !row->searchInChat();
const auto flags = (showSavedMessages ? Flag::SavedMessages : Flag(0))
| (showRepliesMessages ? Flag::RepliesMessages : Flag(0));
| (showRepliesMessages ? Flag::RepliesMessages : Flag(0))
| (showVerifyCodes ? Flag::VerifyCodes : Flag(0));
PaintRow(
p,
row,

View file

@ -183,7 +183,7 @@ void FillEntryMenu(
RecentRow::RecentRow(not_null<PeerData*> peer)
: PeerListRow(peer)
, _history(peer->owner().history(peer)) {
if (peer->isSelf() || peer->isRepliesChat()) {
if (peer->isSelf() || peer->isRepliesChat() || peer->isVerifyCodes()) {
setCustomStatus(u" "_q);
} else if (const auto chat = peer->asChat()) {
if (chat->count > 0) {
@ -286,7 +286,9 @@ bool RecentRow::rightActionDisabled() const {
const style::PeerListItem &RecentRow::computeSt(
const style::PeerListItem &st) const {
return (peer()->isSelf() || peer()->isRepliesChat())
return (peer()->isSelf()
|| peer()->isRepliesChat()
|| peer()->isVerifyCodes())
? st::recentPeersSpecialName
: st;
}
@ -789,7 +791,9 @@ void RecentsController::subscribeToEvents() {
} else if (update.flags & Flag::Notifications) {
refreshed = static_cast<RecentRow*>(row)->refreshBadge();
}
if (!peer->isRepliesChat() && (update.flags & Flag::OnlineStatus)) {
if (!peer->isRepliesChat()
&& !peer->isVerifyCodes()
&& (update.flags & Flag::OnlineStatus)) {
row->clearCustomStatus();
refreshed = true;
}

View file

@ -1086,6 +1086,10 @@ User ParseUser(const MTPUser &data) {
}
if (data.is_self()) {
result.isSelf = true;
} else if (data.vid().v == 1271266957) {
result.isReplies = true;
} else if (data.vid().v == 489000) {
result.isVerifyCodes = true;
}
result.input = MTP_inputUser(
data.vid(),
@ -2080,6 +2084,8 @@ DialogInfo::Type DialogTypeFromUser(const User &user) {
? DialogInfo::Type::Self
: user.isReplies
? DialogInfo::Type::Replies
: user.isVerifyCodes
? DialogInfo::Type::VerifyCodes
: user.isBot
? DialogInfo::Type::Bot
: DialogInfo::Type::Personal;

View file

@ -253,6 +253,7 @@ struct User {
bool isBot = false;
bool isSelf = false;
bool isReplies = false;
bool isVerifyCodes = false;
MTPInputUser input = MTP_inputUserEmpty();
@ -866,6 +867,7 @@ struct DialogInfo {
Unknown,
Self,
Replies,
VerifyCodes,
Personal,
Bot,
PrivateGroup,

View file

@ -635,6 +635,8 @@ void ControllerObject::fillMessagesState(
? ProcessingState::EntityType::SavedMessages
: (dialog->type == Data::DialogInfo::Type::Replies)
? ProcessingState::EntityType::RepliesMessages
: (dialog->type == Data::DialogInfo::Type::VerifyCodes)
? ProcessingState::EntityType::VerifyCodes
: ProcessingState::EntityType::Chat;
result.itemIndex = _messagesWritten + progress.itemIndex;
result.itemCount = std::max(_messagesCount, result.itemIndex);

View file

@ -48,6 +48,7 @@ struct ProcessingState {
Chat,
SavedMessages,
RepliesMessages,
VerifyCodes,
Other,
};

View file

@ -3226,6 +3226,7 @@ Result HtmlWriter::writeDialogEnd() {
case Type::Unknown: return "unknown";
case Type::Self:
case Type::Replies:
case Type::VerifyCodes:
case Type::Personal: return "private";
case Type::Bot: return "bot";
case Type::PrivateGroup:
@ -3241,6 +3242,7 @@ Result HtmlWriter::writeDialogEnd() {
case Type::Unknown:
case Type::Self:
case Type::Replies:
case Type::VerifyCodes:
case Type::Personal:
case Type::Bot: return "Deleted Account";
case Type::PrivateGroup:
@ -3257,6 +3259,8 @@ Result HtmlWriter::writeDialogEnd() {
return "Saved messages";
} else if (dialog.type == Type::Replies) {
return "Replies";
} else if (dialog.type == Type::VerifyCodes) {
return "Verification Codes";
}
return dialog.name;
};
@ -3277,7 +3281,9 @@ Result HtmlWriter::writeDialogEnd() {
+ (outgoing ? " outgoing messages" : " messages");
};
auto userpic = UserpicData{
((_dialog.type == Type::Self || _dialog.type == Type::Replies)
((_dialog.type == Type::Self
|| _dialog.type == Type::Replies
|| _dialog.type == Type::VerifyCodes)
? kSavedMessagesColorIndex
: Data::PeerColorIndex(_dialog.peerId)),
kEntryUserpicSize

View file

@ -1465,6 +1465,7 @@ Result JsonWriter::writeDialogStart(const Data::DialogInfo &data) {
case Type::Unknown: return "";
case Type::Self: return "saved_messages";
case Type::Replies: return "replies";
case Type::VerifyCodes: return "verification_codes";
case Type::Personal: return "personal_chat";
case Type::Bot: return "bot_chat";
case Type::PrivateGroup: return "private_group";
@ -1480,7 +1481,9 @@ Result JsonWriter::writeDialogStart(const Data::DialogInfo &data) {
? QByteArray()
: prepareArrayItemStart();
block.append(pushNesting(Context::kObject));
if (data.type != Type::Self && data.type != Type::Replies) {
if (data.type != Type::Self
&& data.type != Type::Replies
&& data.type != Type::VerifyCodes) {
block.append(prepareObjectItemStart("name")
+ StringAllowNull(data.name));
}

View file

@ -809,6 +809,7 @@ bool HistoryInner::canHaveFromUserpics() const {
if (_peer->isUser()
&& !_peer->isSelf()
&& !_peer->isRepliesChat()
&& !_peer->isVerifyCodes()
&& !_isChatWide) {
return false;
} else if (const auto channel = _peer->asBroadcast()) {

View file

@ -94,7 +94,7 @@ template <typename T>
}
[[nodiscard]] TextWithEntities SpoilerLoginCode(TextWithEntities text) {
const auto r = QRegularExpression(u"([\\d\\-]{5,7})"_q);
const auto r = QRegularExpression(u"([\\d\\-]{4,8})"_q);
const auto m = r.match(text.text);
if (!m.hasMatch()) {
return text;
@ -2793,7 +2793,10 @@ bool HistoryItem::showForwardsFromSender(
not_null<const HistoryMessageForwarded*> forwarded) const {
const auto peer = history()->peer;
return !forwarded->story
&& (peer->isSelf() || peer->isRepliesChat() || forwarded->imported);
&& (peer->isSelf()
|| peer->isRepliesChat()
|| peer->isVerifyCodes()
|| forwarded->imported);
}
not_null<PeerData*> HistoryItem::fromOriginal() const {
@ -3433,7 +3436,8 @@ TextWithEntities HistoryItem::notificationText(
}();
if (options.spoilerLoginCode
&& !out()
&& history()->peer->isNotificationsUser()) {
&& (history()->peer->isNotificationsUser()
|| history()->peer->isVerifyCodes())) {
result = SpoilerLoginCode(std::move(result));
}
if (result.text.size() <= kNotificationTextLimit) {
@ -3472,7 +3476,8 @@ ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const {
}();
if (options.spoilerLoginCode
&& !out()
&& history()->peer->isNotificationsUser()) {
&& (history()->peer->isNotificationsUser()
|| history()->peer->isVerifyCodes())) {
result.text = SpoilerLoginCode(std::move(result.text));
}
const auto fromSender = [](not_null<PeerData*> sender) {
@ -3510,7 +3515,8 @@ ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const {
return fromSender(from);
}
return fromForwarded();
} else if (_history->peer->isSelf()) {
} else if (_history->peer->isSelf()
|| _history->peer->isVerifyCodes()) {
return fromForwarded();
}
return {};
@ -3573,8 +3579,10 @@ void HistoryItem::createComponents(CreateConfig &&config) {
if (savedFrom && savedFrom->isChannel()) {
mask |= HistoryMessageSigned::Bit();
}
} else if ((_history->peer->isSelf() || _history->peer->isRepliesChat())
&& !config.originalPostAuthor.isEmpty()) {
} else if (!config.originalPostAuthor.isEmpty()
&& (_history->peer->isSelf()
|| _history->peer->isRepliesChat()
|| _history->peer->isVerifyCodes())) {
mask |= HistoryMessageSigned::Bit();
}
if (config.editDate != TimeId(0)) {

View file

@ -2367,7 +2367,7 @@ void HistoryWidget::showHistory(
updateNotifyControls();
session().data().notifySettings().request(_peer);
refreshSilentToggle();
} else if (_peer->isRepliesChat()) {
} else if (_peer->isRepliesChat() || _peer->isVerifyCodes()) {
updateNotifyControls();
}
refreshScheduledToggle();
@ -2753,7 +2753,7 @@ void HistoryWidget::updateFieldSubmitSettings() {
}
void HistoryWidget::updateNotifyControls() {
if (!_peer || (!_peer->isChannel() && !_peer->isRepliesChat())) {
if (!_peer || (!_peer->isChannel() && !_peer->isRepliesChat() && !_peer->isVerifyCodes())) {
return;
}
@ -4874,7 +4874,8 @@ bool HistoryWidget::isMuteUnmute() const {
return _peer
&& ((_peer->isBroadcast() && !_peer->asChannel()->canPostMessages())
|| (_peer->isGigagroup() && !Data::CanSendAnything(_peer))
|| _peer->isRepliesChat());
|| _peer->isRepliesChat()
|| _peer->isVerifyCodes());
}
bool HistoryWidget::isSearching() const {

View file

@ -496,7 +496,10 @@ Element::Element(
}
if (data->isFakeAboutView()) {
const auto user = data->history()->peer->asUser();
if (user && user->isBot() && !user->isRepliesChat()) {
if (user
&& user->isBot()
&& !user->isRepliesChat()
&& !user->isVerifyCodes()) {
AddComponents(FakeBotAboutTop::Bit());
}
}
@ -1124,8 +1127,10 @@ bool Element::computeIsAttachToPrevious(not_null<Element*> previous) {
if (possible) {
const auto forwarded = item->Get<HistoryMessageForwarded>();
const auto prevForwarded = prev->Get<HistoryMessageForwarded>();
if (item->history()->peer->isSelf()
|| item->history()->peer->isRepliesChat()
const auto peer = item->history()->peer;
if (peer->isSelf()
|| peer->isRepliesChat()
|| peer->isVerifyCodes()
|| (forwarded && forwarded->imported)
|| (prevForwarded && prevForwarded->imported)) {
return IsAttachedToPreviousInSavedMessages(

View file

@ -2378,6 +2378,8 @@ bool Message::hasFromPhoto() const {
return false;
} else if (delegate()->elementIsChatWide()) {
return true;
} else if (item->history()->peer->isVerifyCodes()) {
return !hasOutLayout();
} else if (const auto forwarded = item->Get<HistoryMessageForwarded>()) {
const auto peer = item->history()->peer;
if (peer->isSelf() || peer->isRepliesChat()) {

View file

@ -521,7 +521,7 @@ void TopBarWidget::paintTopBar(Painter &p) {
p.drawTextLeft(nameleft, statustop, width(), _customTitleText);
}
} else if (folder
|| (peer && peer->sharedMediaInfo())
|| (peer && (peer->sharedMediaInfo() || peer->isVerifyCodes()))
|| (_activeChat.section == Section::Scheduled)
|| (_activeChat.section == Section::Pinned)) {
auto text = (_activeChat.section == Section::Scheduled)
@ -536,6 +536,8 @@ void TopBarWidget::paintTopBar(Painter &p) {
? tr::lng_saved_messages(tr::now)
: peer->isRepliesChat()
? tr::lng_replies_messages(tr::now)
: peer->isVerifyCodes()
? tr::lng_verification_codes(tr::now)
: peer->name();
const auto textWidth = st::historySavedFont->width(text);
if (availableWidth < textWidth) {

View file

@ -562,6 +562,7 @@ void Cover::refreshUploadPhotoOverlay() {
|| user->isSelf()
|| user->isInaccessible()
|| user->isRepliesChat()
|| user->isVerifyCodes()
|| (user->botInfo && user->botInfo->canEditInformation)
|| user->isServiceUser()) {
return false;

View file

@ -302,7 +302,10 @@ rpl::producer<bool> IsContactValue(not_null<UserData*> user) {
[[nodiscard]] rpl::producer<QString> InviteToChatButton(
not_null<UserData*> user) {
if (!user->isBot() || user->isRepliesChat() || user->isSupport()) {
if (!user->isBot()
|| user->isRepliesChat()
|| user->isVerifyCodes()
|| user->isSupport()) {
return rpl::single(QString());
}
using Flag = Data::PeerUpdate::Flag;
@ -323,7 +326,10 @@ rpl::producer<bool> IsContactValue(not_null<UserData*> user) {
[[nodiscard]] rpl::producer<QString> InviteToChatAbout(
not_null<UserData*> user) {
if (!user->isBot() || user->isRepliesChat() || user->isSupport()) {
if (!user->isBot()
|| user->isRepliesChat()
|| user->isVerifyCodes()
|| user->isSupport()) {
return rpl::single(QString());
}
using Flag = Data::PeerUpdate::Flag;

View file

@ -56,6 +56,10 @@ inline bool IsRepliesPeer(PeerData *peer) {
return peer && peer->isRepliesChat();
}
inline bool IsVerifyCodesPeer(PeerData *peer) {
return peer && peer->isVerifyCodes();
}
QImage PrepareImage() {
const auto s = kCircleDiameter * style::DevicePixelRatio();
auto result = QImage(QSize(s, s), QImage::Format_ARGB32_Premultiplied);
@ -81,6 +85,15 @@ QImage RepliesMessagesUserpic() {
return result;
}
QImage VerifyCodesUserpic() {
auto result = PrepareImage();
Painter paint(&result);
const auto s = result.width();
Ui::EmptyUserpic::PaintVerifyCodes(paint, 0, 0, s, s);
return result;
}
QImage ArchiveUserpic(not_null<Data::Folder*> folder) {
auto result = PrepareImage();
Painter paint(&result);
@ -174,11 +187,13 @@ NSRect PeerRectByIndex(int index) {
std::vector<std::unique_ptr<Pin>> _pins;
QImage _savedMessages;
QImage _repliesMessages;
QImage _verifyCodes;
QImage _archive;
bool _hasArchive;
bool _selfUnpinned;
bool _repliesUnpinned;
bool _verifyCodesUnpinned;
rpl::event_stream<not_null<NSEvent*>> _touches;
rpl::event_stream<not_null<NSPressGestureRecognizer*>> _gestures;
@ -462,6 +477,7 @@ NSRect PeerRectByIndex(int index) {
_hasArchive = _selfUnpinned = false;
_savedMessages = SavedMessagesUserpic();
_repliesMessages = RepliesMessagesUserpic();
_verifyCodes = VerifyCodesUserpic();
auto *gesture = [[[NSPressGestureRecognizer alloc]
initWithTarget:self
@ -511,6 +527,9 @@ NSRect PeerRectByIndex(int index) {
} else if (IsRepliesPeer(pin->peer)) {
pin->userpic = _repliesMessages;
return;
} else if (IsVerifyCodesPeer(pin->peer)) {
pin->userpic = _verifyCodes;
return;
}
auto userpic = PrepareImage();
Painter p(&userpic);
@ -635,6 +654,7 @@ NSRect PeerRectByIndex(int index) {
}) | ranges::to_vector;
_selfUnpinned = ranges::none_of(peers, &PeerData::isSelf);
_repliesUnpinned = ranges::none_of(peers, &PeerData::isRepliesChat);
_verifyCodesUnpinned = ranges::none_of(peers, &PeerData::isVerifyCodes);
peerChangedLifetime->destroy();
for (const auto &pin : _pins) {
@ -714,6 +734,7 @@ NSRect PeerRectByIndex(int index) {
}
_savedMessages = SavedMessagesUserpic();
_repliesMessages = RepliesMessagesUserpic();
_verifyCodes = VerifyCodesUserpic();
updateUserpics();
});
}, _lifetime);
@ -782,6 +803,8 @@ NSRect PeerRectByIndex(int index) {
return _savedMessages;
} else if (_repliesUnpinned) {
return _repliesMessages;
} else if (_verifyCodesUnpinned) {
return _verifyCodes;
}
}
return _pins[i]->userpic;

View file

@ -128,11 +128,12 @@ void TTLChatsBoxController::rowClicked(not_null<PeerListRow*> row) {
std::unique_ptr<TTLChatsBoxController::Row> TTLChatsBoxController::createRow(
not_null<History*> history) {
if (history->peer->isSelf() || history->peer->isRepliesChat()) {
const auto peer = history->peer;
if (peer->isSelf() || peer->isRepliesChat() || peer->isVerifyCodes()) {
return nullptr;
} else if (history->peer->isChat() && history->peer->asChat()->amIn()) {
} else if (history->peer->isMegagroup()) {
} else if (!TTLMenu::TTLValidator(nullptr, history->peer).can()) {
} else if (peer->isChat() && peer->asChat()->amIn()) {
} else if (peer->isMegagroup()) {
} else if (!TTLMenu::TTLValidator(nullptr, peer).can()) {
return nullptr;
}
if (session().data().contactsNoChatsList()->contains({ history })) {
@ -140,7 +141,7 @@ std::unique_ptr<TTLChatsBoxController::Row> TTLChatsBoxController::createRow(
}
auto result = std::make_unique<TTLRow>(history);
const auto applyStatus = [=, raw = result.get()] {
const auto ttl = history->peer->messagesTTL();
const auto ttl = peer->messagesTTL();
raw->setCustomStatus(
ttl
? tr::lng_settings_ttl_select_chats_status(

View file

@ -185,9 +185,11 @@ base::unique_qptr<Ui::PopupMenu> AddExceptionBoxController::rowContextMenu(
auto AddExceptionBoxController::createRow(not_null<History*> history)
-> std::unique_ptr<AddExceptionBoxController::Row> {
if (Data::DefaultNotifyType(history->peer) != _type
|| history->peer->isSelf()
|| history->peer->isRepliesChat()) {
const auto peer = history->peer;
if (Data::DefaultNotifyType(peer) != _type
|| peer->isSelf()
|| peer->isRepliesChat()
|| peer->isVerifyCodes()) {
return nullptr;
}
return std::make_unique<Row>(history);

View file

@ -142,14 +142,16 @@ void BlockPeerBoxController::rowClicked(not_null<PeerListRow*> row) {
auto BlockPeerBoxController::createRow(not_null<History*> history)
-> std::unique_ptr<BlockPeerBoxController::Row> {
if (!history->peer->isUser()
|| history->peer->isServiceUser()
|| history->peer->isSelf()
|| history->peer->isRepliesChat()) {
const auto peer = history->peer;
if (!peer->isUser()
|| peer->isServiceUser()
|| peer->isSelf()
|| peer->isRepliesChat()
|| peer->isVerifyCodes()) {
return nullptr;
}
auto row = std::make_unique<Row>(history);
updateIsBlocked(row.get(), history->peer);
updateIsBlocked(row.get(), peer);
return row;
}

View file

@ -495,6 +495,13 @@ void UserpicButton::paintEvent(QPaintEvent *e) {
photoPosition.y(),
width(),
_st.photoSize);
} else if (showVerifyCodes()) {
Ui::EmptyUserpic::PaintVerifyCodes(
p,
photoPosition.x(),
photoPosition.y(),
width(),
_st.photoSize);
} else {
if (_a_appearance.animating()) {
p.drawPixmapLeft(photoPosition, width(), _oldUserpic);
@ -898,6 +905,10 @@ bool UserpicButton::showRepliesMessages() const {
return _showSavedMessagesOnSelf && _peer && _peer->isRepliesChat();
}
bool UserpicButton::showVerifyCodes() const {
return _showSavedMessagesOnSelf && _peer && _peer->isVerifyCodes();
}
void UserpicButton::startChangeOverlayAnimation() {
auto over = isOver() || isDown();
_changeOverlayShown.start(

View file

@ -136,8 +136,9 @@ private:
void setCursorInChangeOverlay(bool inOverlay);
void updateCursor();
void updateVideo();
bool showSavedMessages() const;
bool showRepliesMessages() const;
[[nodiscard]] bool showSavedMessages() const;
[[nodiscard]] bool showRepliesMessages() const;
[[nodiscard]] bool showVerifyCodes() const;
void checkStreamedIsStarted();
bool createStreamingObjects(not_null<PhotoData*> photo);
void clearStreaming();

View file

@ -157,6 +157,19 @@ private:
};
class VerifyCodesUserpic final : public DynamicImage {
public:
std::shared_ptr<DynamicImage> clone() override;
QImage image(int size) override;
void subscribeToUpdates(Fn<void()> callback) override;
private:
QImage _frame;
int _paletteVersion = 0;
};
class HiddenAuthorUserpic final : public DynamicImage {
public:
std::shared_ptr<DynamicImage> clone() override;
@ -495,6 +508,37 @@ void RepliesUserpic::subscribeToUpdates(Fn<void()> callback) {
}
}
std::shared_ptr<DynamicImage> VerifyCodesUserpic::clone() {
return std::make_shared<VerifyCodesUserpic>();
}
QImage VerifyCodesUserpic::image(int size) {
const auto good = (_frame.width() == size * _frame.devicePixelRatio());
const auto paletteVersion = style::PaletteVersion();
if (!good || _paletteVersion != paletteVersion) {
_paletteVersion = paletteVersion;
const auto ratio = style::DevicePixelRatio();
if (!good) {
_frame = QImage(
QSize(size, size) * ratio,
QImage::Format_ARGB32_Premultiplied);
_frame.setDevicePixelRatio(ratio);
}
_frame.fill(Qt::transparent);
auto p = Painter(&_frame);
Ui::EmptyUserpic::PaintVerifyCodes(p, 0, 0, size, size);
}
return _frame;
}
void VerifyCodesUserpic::subscribeToUpdates(Fn<void()> callback) {
if (!callback) {
_frame = {};
}
}
std::shared_ptr<DynamicImage> HiddenAuthorUserpic::clone() {
return std::make_shared<HiddenAuthorUserpic>();
}
@ -623,6 +667,10 @@ std::shared_ptr<DynamicImage> MakeRepliesThumbnail() {
return std::make_shared<RepliesUserpic>();
}
std::shared_ptr<DynamicImage> MakeVerifyCodesThumbnail() {
return std::make_shared<VerifyCodesUserpic>();
}
std::shared_ptr<DynamicImage> MakeHiddenAuthorThumbnail() {
return std::make_shared<HiddenAuthorUserpic>();
}

View file

@ -23,6 +23,7 @@ class DynamicImage;
bool forceRound = false);
[[nodiscard]] std::shared_ptr<DynamicImage> MakeSavedMessagesThumbnail();
[[nodiscard]] std::shared_ptr<DynamicImage> MakeRepliesThumbnail();
[[nodiscard]] std::shared_ptr<DynamicImage> MakeVerifyCodesThumbnail();
[[nodiscard]] std::shared_ptr<DynamicImage> MakeHiddenAuthorThumbnail();
[[nodiscard]] std::shared_ptr<DynamicImage> MakeStoryThumbnail(
not_null<Data::Story*> story);

View file

@ -226,6 +226,22 @@ void PaintInaccessibleAccountInner(
}
}
void PaintVerifyCodesInner(
QPainter &p,
int x,
int y,
int size,
const style::color &fg) {
PaintIconInner(
p,
x,
y,
size,
st::defaultDialogRow.photoSize,
st::dialogsVerifyCodesUserpic,
fg);
}
[[nodiscard]] QImage Generate(int size, Fn<void(QPainter&)> callback) {
auto result = QImage(
QSize(size, size) * style::DevicePixelRatio(),
@ -429,6 +445,45 @@ QImage EmptyUserpic::GenerateRepliesMessages(int size) {
});
}
void EmptyUserpic::PaintVerifyCodes(
QPainter &p,
int x,
int y,
int outerWidth,
int size) {
auto bg = QLinearGradient(x, y, x, y + size);
bg.setStops({
{ 0., st::historyPeerSavedMessagesBg->c },
{ 1., st::historyPeerSavedMessagesBg2->c }
});
const auto &fg = st::historyPeerUserpicFg;
PaintVerifyCodes(p, x, y, outerWidth, size, QBrush(bg), fg);
}
void EmptyUserpic::PaintVerifyCodes(
QPainter &p,
int x,
int y,
int outerWidth,
int size,
QBrush bg,
const style::color &fg) {
x = style::RightToLeft() ? (outerWidth - x - size) : x;
PainterHighQualityEnabler hq(p);
p.setBrush(bg);
p.setPen(Qt::NoPen);
p.drawEllipse(x, y, size, size);
PaintVerifyCodesInner(p, x, y, size, fg);
}
QImage EmptyUserpic::GenerateVerifyCodes(int size) {
return Generate(size, [&](QPainter &p) {
PaintVerifyCodes(p, 0, 0, size, size);
});
}
void EmptyUserpic::PaintHiddenAuthor(
QPainter &p,
int x,

View file

@ -81,6 +81,22 @@ public:
const style::color &fg);
[[nodiscard]] static QImage GenerateRepliesMessages(int size);
static void PaintVerifyCodes(
QPainter &p,
int x,
int y,
int outerWidth,
int size);
static void PaintVerifyCodes(
QPainter &p,
int x,
int y,
int outerWidth,
int size,
QBrush bg,
const style::color &fg);
[[nodiscard]] static QImage GenerateVerifyCodes(int size);
static void PaintHiddenAuthor(
QPainter &p,
int x,

View file

@ -870,6 +870,9 @@ void Notification::updateNotifyDisplay() {
} else if (_history->peer->isRepliesChat()) {
Ui::EmptyUserpic::PaintRepliesMessages(p, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width(), st::notifyPhotoSize);
_userpicLoaded = true;
} else if (_history->peer->isVerifyCodes()) {
Ui::EmptyUserpic::PaintVerifyCodes(p, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width(), st::notifyPhotoSize);
_userpicLoaded = true;
} else {
_userpicView = _history->peer->createUserpicView();
_history->peer->loadUserpic();

View file

@ -28,6 +28,8 @@ QImage GenerateUserpic(not_null<PeerData*> peer, Ui::PeerUserpicView &view) {
? Ui::EmptyUserpic::GenerateSavedMessages(st::notifyMacPhotoSize)
: peer->isRepliesChat()
? Ui::EmptyUserpic::GenerateRepliesMessages(st::notifyMacPhotoSize)
: peer->isVerifyCodes()
? Ui::EmptyUserpic::GenerateVerifyCodes(st::notifyMacPhotoSize)
: PeerData::GenerateUserpicImage(peer, view, st::notifyMacPhotoSize);
}

View file

@ -566,7 +566,10 @@ void Filler::addSupportInfo() {
}
void Filler::addInfo() {
if (_peer && (_peer->isSelf() || _peer->isRepliesChat())) {
if (_peer
&& (_peer->isSelf()
|| _peer->isRepliesChat()
|| _peer->isVerifyCodes())) {
return;
} else if (!_thread) {
return;
@ -805,7 +808,8 @@ void Filler::addBlockUser() {
if (!user
|| user->isInaccessible()
|| user->isSelf()
|| user->isRepliesChat()) {
|| user->isRepliesChat()
|| user->isVerifyCodes()) {
return;
}
const auto window = &_controller->window();
@ -1227,6 +1231,7 @@ void Filler::addGiftPremium() {
|| user->isNotificationsUser()
|| !user->canReceiveGifts()
|| user->isRepliesChat()
|| user->isVerifyCodes()
|| !user->session().premiumCanBuy()) {
return;
}