From 0c43aabfeca7892a27eab198c7001b973b192243 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 5 Jul 2017 21:11:31 +0300 Subject: [PATCH] Allow to ban from actions log user context menu. --- .../history/history_admin_log_inner.cpp | 262 +++++++++++++----- .../history/history_admin_log_inner.h | 14 +- .../history/history_admin_log_item.cpp | 2 +- .../history/history_admin_log_section.cpp | 40 +-- .../history/history_admin_log_section.h | 10 +- .../SourceFiles/history/history_service.cpp | 8 +- .../SourceFiles/history/history_service.h | 2 +- Telegram/SourceFiles/structs.cpp | 37 +-- Telegram/SourceFiles/structs.h | 19 +- 9 files changed, 266 insertions(+), 128 deletions(-) diff --git a/Telegram/SourceFiles/history/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/history_admin_log_inner.cpp index a72d14ffe..49e537fde 100644 --- a/Telegram/SourceFiles/history/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_inner.cpp @@ -25,18 +25,23 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "history/history_message.h" #include "history/history_service_layout.h" #include "history/history_admin_log_section.h" +#include "history/history_admin_log_filter.h" #include "chat_helpers/message_field.h" #include "mainwindow.h" #include "mainwidget.h" +#include "apiwrap.h" #include "window/window_controller.h" #include "auth_session.h" #include "ui/widgets/popup_menu.h" #include "core/file_utilities.h" #include "lang/lang_keys.h" +#include "boxes/edit_participant_box.h" namespace AdminLog { namespace { +// If we require to support more admins we'll have to rewrite this anyway. +constexpr auto kMaxChannelAdmins = 200; constexpr auto kScrollDateHideTimeout = 1000; constexpr auto kEventsFirstPage = 20; constexpr auto kEventsPerPage = 50; @@ -223,6 +228,8 @@ InnerWidget::InnerWidget(QWidget *parent, gsl::not_null con } }); updateEmptyText(); + + requestAdmins(); } void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { @@ -326,6 +333,47 @@ void InnerWidget::applySearch(const QString &query) { } } +void InnerWidget::requestAdmins() { + request(MTPchannels_GetParticipants(_channel->inputChannel, MTP_channelParticipantsAdmins(), MTP_int(0), MTP_int(kMaxChannelAdmins))).done([this](const MTPchannels_ChannelParticipants &result) { + Expects(result.type() == mtpc_channels_channelParticipants); + auto &participants = result.c_channels_channelParticipants(); + App::feedUsers(participants.vusers); + for (auto &participant : participants.vparticipants.v) { + auto getUserId = [&participant] { + switch (participant.type()) { + case mtpc_channelParticipant: return participant.c_channelParticipant().vuser_id.v; + case mtpc_channelParticipantSelf: return participant.c_channelParticipantSelf().vuser_id.v; + case mtpc_channelParticipantAdmin: return participant.c_channelParticipantAdmin().vuser_id.v; + case mtpc_channelParticipantCreator: return participant.c_channelParticipantCreator().vuser_id.v; + case mtpc_channelParticipantBanned: return participant.c_channelParticipantBanned().vuser_id.v; + default: Unexpected("Type in AdminLog::Widget::showFilter()"); + } + }; + if (auto user = App::userLoaded(getUserId())) { + _admins.push_back(user); + auto canEdit = (participant.type() == mtpc_channelParticipantAdmin) && (participant.c_channelParticipantAdmin().is_can_edit()); + if (canEdit) { + _adminsCanEdit.push_back(user); + } + } + } + if (_admins.empty()) { + _admins.push_back(App::self()); + } + if (_showFilterCallback) { + showFilter(std::move(_showFilterCallback)); + } + }).send(); +} + +void InnerWidget::showFilter(base::lambda callback) { + if (_admins.empty()) { + _showFilterCallback = std::move(callback); + } else { + Ui::show(Box(_channel, _admins, _filter, std::move(callback))); + } +} + void InnerWidget::clearAndRequestLog() { request(base::take(_preloadUpRequestId)).cancel(); request(base::take(_preloadDownRequestId)).cancel(); @@ -374,6 +422,8 @@ QPoint InnerWidget::tooltipPos() const { void InnerWidget::saveState(gsl::not_null memento) { memento->setFilter(std::move(_filter)); + memento->setAdmins(std::move(_admins)); + memento->setAdminsCanEdit(std::move(_adminsCanEdit)); memento->setSearchQuery(std::move(_searchQuery)); if (!_filterChanged) { memento->setItems(std::move(_items), std::move(_itemsByIds), _upLoaded, _downLoaded); @@ -386,6 +436,8 @@ void InnerWidget::restoreState(gsl::not_null memento) { _items = memento->takeItems(); _itemsByIds = memento->takeItemsByIds(); _idManager = memento->takeIdManager(); + _admins = memento->takeAdmins(); + _adminsCanEdit = memento->takeAdminsCanEdit(); _filter = memento->takeFilter(); _searchQuery = memento->takeSearchQuery(); _upLoaded = memento->upLoaded(); @@ -427,65 +479,9 @@ void InnerWidget::preloadMore(Direction direction) { auto &results = result.c_channels_adminLogResults(); App::feedUsers(results.vusers); App::feedChats(results.vchats); - - if (loadedFlag) { - return; + if (!loadedFlag) { + addEvents(direction, results.vevents.v); } - - if (_filterChanged) { - clearAfterFilterChange(); - } - - auto &events = results.vevents.v; - if (!events.empty()) { - auto oldItemsCount = _items.size(); - _items.reserve(oldItemsCount + events.size() * 2); - for_const (auto &event, events) { - t_assert(event.type() == mtpc_channelAdminLogEvent); - auto &data = event.c_channelAdminLogEvent(); - if (_itemsByIds.find(data.vid.v) != _itemsByIds.cend()) { - continue; - } - - auto count = 0; - GenerateItems(_history, _idManager, data, [this, id = data.vid.v, &count](HistoryItemOwned item) { - _itemsByIds.emplace(id, item.get()); - _items.push_back(std::move(item)); - ++count; - }); - if (count > 1) { - // Reverse the inner order of the added messages, because we load events - // from bottom to top but inside one event they go from top to bottom. - auto full = _items.size(); - auto from = full - count; - for (auto i = 0, toReverse = count / 2; i != toReverse; ++i) { - std::swap(_items[from + i], _items[full - i - 1]); - } - } - } - auto newItemsCount = _items.size(); - if (newItemsCount != oldItemsCount) { - for (auto i = oldItemsCount; i != newItemsCount + 1; ++i) { - if (i > 0) { - auto item = _items[i - 1].get(); - if (i == newItemsCount) { - item->setLogEntryDisplayDate(true); - } else { - auto previous = _items[i].get(); - item->setLogEntryDisplayDate(item->date.date() != previous->date.date()); - auto attachToPrevious = item->computeIsAttachToPrevious(previous); - item->setLogEntryAttachToPrevious(attachToPrevious); - previous->setLogEntryAttachToNext(attachToPrevious); - } - } - } - updateMinMaxIds(); - itemsAdded(direction); - } - } else { - loadedFlag = true; - } - update(); }).fail([this, &requestId, &loadedFlag](const RPCError &error) { requestId = 0; loadedFlag = true; @@ -493,6 +489,61 @@ void InnerWidget::preloadMore(Direction direction) { }).send(); } +void InnerWidget::addEvents(Direction direction, const QVector &events) { + if (_filterChanged) { + clearAfterFilterChange(); + } + + auto up = (direction == Direction::Up); + if (events.empty()) { + (up ? _upLoaded : _downLoaded) = true; + update(); + return; + } + + // When loading items up we just add them to the back of the _items vector. + // When loading items down we add them to a new vector and copy _items after them. + auto newItemsForDownDirection = std::vector(); + auto oldItemsCount = _items.size(); + auto &addToItems = (direction == Direction::Up) ? _items : newItemsForDownDirection; + addToItems.reserve(oldItemsCount + events.size() * 2); + for_const (auto &event, events) { + t_assert(event.type() == mtpc_channelAdminLogEvent); + auto &data = event.c_channelAdminLogEvent(); + if (_itemsByIds.find(data.vid.v) != _itemsByIds.cend()) { + continue; + } + + auto count = 0; + GenerateItems(_history, _idManager, data, [this, id = data.vid.v, &addToItems, &count](HistoryItemOwned item) { + _itemsByIds.emplace(id, item.get()); + addToItems.push_back(std::move(item)); + ++count; + }); + if (count > 1) { + // Reverse the inner order of the added messages, because we load events + // from bottom to top but inside one event they go from top to bottom. + auto full = addToItems.size(); + auto from = full - count; + for (auto i = 0, toReverse = count / 2; i != toReverse; ++i) { + std::swap(addToItems[from + i], addToItems[full - i - 1]); + } + } + } + auto newItemsCount = _items.size() + ((direction == Direction::Up) ? 0 : newItemsForDownDirection.size()); + if (newItemsCount != oldItemsCount) { + if (direction == Direction::Down) { + for (auto &item : _items) { + newItemsForDownDirection.push_back(std::move(item)); + } + _items = std::move(newItemsForDownDirection); + } + updateMinMaxIds(); + itemsAdded(direction, newItemsCount - oldItemsCount); + } + update(); +} + void InnerWidget::updateMinMaxIds() { if (_itemsByIds.empty() || _filterChanged) { _maxId = _minId = 0; @@ -505,7 +556,24 @@ void InnerWidget::updateMinMaxIds() { } } -void InnerWidget::itemsAdded(Direction direction) { +void InnerWidget::itemsAdded(Direction direction, int addedCount) { + Expects(addedCount >= 0); + auto checkFrom = (direction == Direction::Up) ? (_items.size() - addedCount) : 1; // Should be ": 0", but zero is skipped anyway. + auto checkTo = (direction == Direction::Up) ? (_items.size() + 1) : (addedCount + 1); + for (auto i = checkFrom; i != checkTo; ++i) { + if (i > 0) { + auto item = _items[i - 1].get(); + if (i < _items.size()) { + auto previous = _items[i].get(); + item->setLogEntryDisplayDate(item->date.date() != previous->date.date()); + auto attachToPrevious = item->computeIsAttachToPrevious(previous); + item->setLogEntryAttachToPrevious(attachToPrevious); + previous->setLogEntryAttachToNext(attachToPrevious); + } else { + item->setLogEntryDisplayDate(true); + } + } + } updateSize(); } @@ -731,9 +799,10 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { auto item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem(); auto lnkPhoto = dynamic_cast(_contextMenuLink.data()); auto lnkDocument = dynamic_cast(_contextMenuLink.data()); - bool lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideo() : false; - bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false; - bool lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false; + auto lnkPeer = dynamic_cast(_contextMenuLink.data()); + auto lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideo() : false; + auto lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false; + auto lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false; if (lnkPhoto || lnkDocument) { if (isUponSelected > 0) { _menu->addAction(lang(lng_context_copy_selected), [this] { copySelectedText(); })->setEnabled(true); @@ -766,6 +835,10 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (App::hoveredLinkItem()) { App::contextItem(App::hoveredLinkItem()); } + } else if (lnkPeer) { // suggest to block + if (auto user = lnkPeer->peer()->asUser()) { + suggestRestrictUser(user); + } } else { // maybe cursor on some text history item? bool canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg()); bool canForward = item && item->canForward(); @@ -934,6 +1007,71 @@ void InnerWidget::setToClipboard(const TextWithEntities &forClipboard, QClipboar } } +void InnerWidget::suggestRestrictUser(gsl::not_null user) { + Expects(_menu != nullptr); + if (!_channel->isMegagroup() || !_channel->canBanMembers() || _admins.empty()) { + return; + } + if (base::contains(_admins, user)) { + if (!base::contains(_adminsCanEdit, user)) { + return; + } + } + _menu->addAction(lang(lng_context_restrict_user), [this, user] { + auto editRestrictions = [user, this](bool hasAdminRights, const MTPChannelBannedRights ¤tRights) { + auto weak = QPointer(this); + auto box = std::make_shared>(); + *box = Ui::show(Box(_channel, user, hasAdminRights, currentRights, [user, weak, box](const MTPChannelBannedRights &rights) { + if (weak) { + weak->restrictUser(user, rights); + } + if (*box) { + (*box)->closeBox(); + } + }), KeepOtherLayers); + }; + if (base::contains(_admins, user)) { + editRestrictions(true, EditRestrictedBox::DefaultRights(_channel)); + } else { + request(MTPchannels_GetParticipant(_channel->inputChannel, user->inputUser)).done([this, editRestrictions](const MTPchannels_ChannelParticipant &result) { + Expects(result.type() == mtpc_channels_channelParticipant); + auto &participant = result.c_channels_channelParticipant(); + App::feedUsers(participant.vusers); + auto type = participant.vparticipant.type(); + if (type == mtpc_channelParticipantBanned) { + editRestrictions(false, participant.vparticipant.c_channelParticipantBanned().vbanned_rights); + } else { + auto hasAdminRights = (type == mtpc_channelParticipantAdmin || type == mtpc_channelParticipantCreator); + editRestrictions(hasAdminRights, EditRestrictedBox::DefaultRights(_channel)); + } + }).fail([this, editRestrictions](const RPCError &error) { + editRestrictions(false, EditRestrictedBox::DefaultRights(_channel)); + }).send(); + } + }); +} + +void InnerWidget::restrictUser(gsl::not_null user, const MTPChannelBannedRights &rights) { + auto weak = QPointer(this); + MTP::send(MTPchannels_EditBanned(_channel->inputChannel, user->inputUser, rights), rpcDone([megagroup = _channel.get(), user, weak, rights](const MTPUpdates &result) { + AuthSession::Current().api().applyUpdates(result); + megagroup->applyEditBanned(user, rights); + if (weak) { + weak->restrictUserDone(user, rights); + } + })); +} + +void InnerWidget::restrictUserDone(gsl::not_null user, const MTPChannelBannedRights &rights) { + Expects(rights.type() == mtpc_channelBannedRights); + if (rights.c_channelBannedRights().vflags.v) { + _admins.erase(std::remove(_admins.begin(), _admins.end(), user), _admins.end()); + _adminsCanEdit.erase(std::remove(_adminsCanEdit.begin(), _adminsCanEdit.end(), user), _adminsCanEdit.end()); + } + _downLoaded = false; + checkPreloadMore(); +} + void InnerWidget::mousePressEvent(QMouseEvent *e) { if (_menu) { e->accept(); diff --git a/Telegram/SourceFiles/history/history_admin_log_inner.h b/Telegram/SourceFiles/history/history_admin_log_inner.h index b445ccd56..3600a6ef3 100644 --- a/Telegram/SourceFiles/history/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/history_admin_log_inner.h @@ -66,10 +66,8 @@ public: // Empty "flags" means all events. void applyFilter(FilterValue &&value); - FilterValue filter() const { - return _filter; - } void applySearch(const QString &query); + void showFilter(base::lambda callback); // AbstractTooltipShower interface QString tooltipText() const override; @@ -131,17 +129,22 @@ private: void copySelectedText(); TextWithEntities getSelectedText() const; void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard); + void suggestRestrictUser(gsl::not_null user); + void restrictUser(gsl::not_null user, const MTPChannelBannedRights &rights); + void restrictUserDone(gsl::not_null user, const MTPChannelBannedRights &rights); + void requestAdmins(); void checkPreloadMore(); void updateVisibleTopItem(); void preloadMore(Direction direction); - void itemsAdded(Direction direction); + void itemsAdded(Direction direction, int addedCount); void updateSize(); void updateMinMaxIds(); void updateEmptyText(); void paintEmpty(Painter &p); void clearAfterFilterChange(); void clearAndRequestLog(); + void addEvents(Direction direction, const QVector &events); void toggleScrollDateShown(); void repaintScrollDateCallback(); @@ -232,6 +235,9 @@ private: FilterValue _filter; QString _searchQuery; + std::vector> _admins; + std::vector> _adminsCanEdit; + base::lambda _showFilterCallback; }; diff --git a/Telegram/SourceFiles/history/history_admin_log_item.cpp b/Telegram/SourceFiles/history/history_admin_log_item.cpp index 1a51b7c12..54dddc693 100644 --- a/Telegram/SourceFiles/history/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_item.cpp @@ -250,7 +250,7 @@ void GenerateItems(gsl::not_null history, LocalIdManager &idManager, c using Flag = MTPDmessage::Flag; auto fromName = App::peerName(from); - auto fromLink = peerOpenClickHandler(from); + auto fromLink = from->createOpenLink(); auto fromLinkText = textcmdLink(1, fromName); auto addSimpleServiceMessage = [&](const QString &text, PhotoData *photo = nullptr) { diff --git a/Telegram/SourceFiles/history/history_admin_log_section.cpp b/Telegram/SourceFiles/history/history_admin_log_section.cpp index f5b7b3291..2cfd10cfe 100644 --- a/Telegram/SourceFiles/history/history_admin_log_section.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_section.cpp @@ -39,9 +39,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace AdminLog { -// If we require to support more admins we'll have to rewrite this anyway. -constexpr auto kMaxChannelAdmins = 200; - class FixedBar final : public TWidget, private base::Subscriber { public: FixedBar(QWidget *parent, gsl::not_null channel); @@ -264,37 +261,10 @@ Widget::Widget(QWidget *parent, gsl::not_null controller, g } void Widget::showFilter() { - if (_admins.empty()) { - request(MTPchannels_GetParticipants(_inner->channel()->inputChannel, MTP_channelParticipantsAdmins(), MTP_int(0), MTP_int(kMaxChannelAdmins))).done([this](const MTPchannels_ChannelParticipants &result) { - Expects(result.type() == mtpc_channels_channelParticipants); - auto &participants = result.c_channels_channelParticipants(); - App::feedUsers(participants.vusers); - for (auto &participant : participants.vparticipants.v) { - auto getUserId = [&participant] { - switch (participant.type()) { - case mtpc_channelParticipant: return participant.c_channelParticipant().vuser_id.v; - case mtpc_channelParticipantSelf: return participant.c_channelParticipantSelf().vuser_id.v; - case mtpc_channelParticipantAdmin: return participant.c_channelParticipantAdmin().vuser_id.v; - case mtpc_channelParticipantCreator: return participant.c_channelParticipantCreator().vuser_id.v; - case mtpc_channelParticipantBanned: return participant.c_channelParticipantBanned().vuser_id.v; - default: Unexpected("Type in AdminLog::Widget::showFilter()"); - } - }; - if (auto user = App::userLoaded(getUserId())) { - _admins.push_back(user); - } - } - if (_admins.empty()) { - _admins.push_back(App::self()); - } - showFilter(); - }).send(); - } else { - Ui::show(Box(_inner->channel(), _admins, _inner->filter(), [this](FilterValue &&filter) { - applyFilter(std::move(filter)); - Ui::hideLayer(); - })); - } + _inner->showFilter([this](FilterValue &&filter) { + applyFilter(std::move(filter)); + Ui::hideLayer(); + }); } void Widget::updateAdaptiveLayout() { @@ -350,13 +320,11 @@ std::unique_ptr Widget::createMemento() { void Widget::saveState(gsl::not_null memento) { memento->setScrollTop(_scroll->scrollTop()); - memento->setAdmins(std::move(_admins)); _inner->saveState(memento); } void Widget::restoreState(gsl::not_null memento) { _inner->restoreState(memento); - _admins = memento->takeAdmins(); auto scrollTop = memento->getScrollTop(); _scroll->scrollToY(scrollTop); _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); diff --git a/Telegram/SourceFiles/history/history_admin_log_section.h b/Telegram/SourceFiles/history/history_admin_log_section.h index 0535dac6b..d213eec0a 100644 --- a/Telegram/SourceFiles/history/history_admin_log_section.h +++ b/Telegram/SourceFiles/history/history_admin_log_section.h @@ -80,7 +80,7 @@ private: }; -class Widget final : public Window::SectionWidget, private MTP::Sender { +class Widget final : public Window::SectionWidget { public: Widget(QWidget *parent, gsl::not_null controller, gsl::not_null channel); @@ -128,7 +128,6 @@ private: object_ptr _fixedBar; object_ptr _fixedBarShadow; object_ptr _whatIsThis; - std::vector> _admins; }; @@ -152,9 +151,15 @@ public: void setAdmins(std::vector> admins) { _admins = std::move(admins); } + void setAdminsCanEdit(std::vector> admins) { + _adminsCanEdit = std::move(admins); + } std::vector> takeAdmins() { return std::move(_admins); } + std::vector> takeAdminsCanEdit() { + return std::move(_adminsCanEdit); + } void setItems(std::vector &&items, std::map &&itemsByIds, bool upLoaded, bool downLoaded) { _items = std::move(items); @@ -197,6 +202,7 @@ private: gsl::not_null _channel; int _scrollTop = 0; std::vector> _admins; + std::vector> _adminsCanEdit; std::vector _items; std::map _itemsByIds; bool _upLoaded = false; diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index 7018bb253..61f365eb0 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -53,7 +53,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) { result.text = lng_action_user_joined(lt_from, fromLinkText()); } else { result.links.push_back(fromLink()); - result.links.push_back(peerOpenClickHandler(u)); + result.links.push_back(u->createOpenLink()); result.text = lng_action_add_user(lt_from, fromLinkText(), lt_user, textcmdLink(2, u->name)); } } else if (users.isEmpty()) { @@ -63,7 +63,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) { result.links.push_back(fromLink()); for (auto i = 0, l = users.size(); i != l; ++i) { auto user = App::user(peerFromUser(users[i])); - result.links.push_back(peerOpenClickHandler(user)); + result.links.push_back(user->createOpenLink()); auto linkText = textcmdLink(i + 2, user->name); if (i == 0) { @@ -123,7 +123,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) { } else { auto user = App::user(peerFromUser(action.vuser_id)); result.links.push_back(fromLink()); - result.links.push_back(peerOpenClickHandler(user)); + result.links.push_back(user->createOpenLink()); result.text = lng_action_kick_user(lt_from, fromLinkText(), lt_user, textcmdLink(2, user->name)); } return result; @@ -687,7 +687,7 @@ HistoryJoined::PreparedText HistoryJoined::GenerateText(gsl::not_null return { lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined) }; } auto result = PreparedText {}; - result.links.push_back(peerOpenClickHandler(inviter)); + result.links.push_back(inviter->createOpenLink()); result.text = (history->isMegagroup() ? lng_action_add_you_group : lng_action_add_you)(lt_from, textcmdLink(1, inviter->name)); return result; } diff --git a/Telegram/SourceFiles/history/history_service.h b/Telegram/SourceFiles/history/history_service.h index 2129036e4..be1db8145 100644 --- a/Telegram/SourceFiles/history/history_service.h +++ b/Telegram/SourceFiles/history/history_service.h @@ -115,7 +115,7 @@ protected: return textcmdLink(1, _from->name); }; ClickHandlerPtr fromLink() const { - return peerOpenClickHandler(_from); + return _from->createOpenLink(); }; void removeMedia(); diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 6a56d7281..982e6327b 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -248,6 +248,23 @@ using UpdateFlag = Notify::PeerUpdate::Flag; NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats; NotifySettingsPtr globalNotifyAllPtr = UnknownNotifySettings, globalNotifyUsersPtr = UnknownNotifySettings, globalNotifyChatsPtr = UnknownNotifySettings; +PeerClickHandler::PeerClickHandler(gsl::not_null peer) : _peer(peer) { +} + +void PeerClickHandler::onClick(Qt::MouseButton button) const { + if (button == Qt::LeftButton && App::main()) { + if (_peer && _peer->isChannel() && App::main()->historyPeer() != _peer) { + if (!_peer->asChannel()->isPublic() && !_peer->asChannel()->amIn()) { + Ui::show(Box(lang((_peer->isMegagroup()) ? lng_group_not_accessible : lng_channel_not_accessible))); + } else { + Ui::showPeerHistory(_peer, ShowAtUnreadMsgId, Ui::ShowWay::Forward); + } + } else { + Ui::showPeerProfile(_peer); + } + } +} + PeerData::PeerData(const PeerId &id) : id(id), _colorIndex(peerColorIndex(id)) { nameText.setText(st::msgNameStyle, QString(), _textNameOptions); _userpicEmpty.set(_colorIndex, QString()); @@ -304,6 +321,10 @@ void PeerData::updateNameDelayed(const QString &newName, const QString &newNameO Notify::peerUpdatedDelayed(update); } +ClickHandlerPtr PeerData::createOpenLink() { + return MakeShared(this); +} + void PeerData::setUserpic(ImagePtr userpic) { _userpic = userpic; if (!_userpic || !_userpic->loaded()) { @@ -2106,22 +2127,6 @@ GameData::GameData(const GameId &id, const uint64 &accessHash, const QString &sh , document(document) { } -ClickHandlerPtr peerOpenClickHandler(PeerData *peer) { - return MakeShared([peer] { - if (App::main()) { - if (peer && peer->isChannel() && App::main()->historyPeer() != peer) { - if (!peer->asChannel()->isPublic() && !peer->asChannel()->amIn()) { - Ui::show(Box(lang((peer->isMegagroup()) ? lng_group_not_accessible : lng_channel_not_accessible))); - } else { - Ui::showPeerHistory(peer, ShowAtUnreadMsgId, Ui::ShowWay::Forward); - } - } else { - Ui::showPeerProfile(peer); - } - } - }); -} - MsgId clientMsgId() { static MsgId currentClientMsgId = StartClientMsgId; t_assert(currentClientMsgId < EndClientMsgId); diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 9b867e48b..9a0284e9a 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -267,7 +267,21 @@ inline const QString &emptyUsername() { return empty; } -ClickHandlerPtr peerOpenClickHandler(PeerData *peer); +class PeerData; + +class PeerClickHandler : public ClickHandler { +public: + PeerClickHandler(gsl::not_null peer); + void onClick(Qt::MouseButton button) const override; + + gsl::not_null peer() const { + return _peer; + } + +private: + gsl::not_null _peer; + +}; class UserData; class ChatData; @@ -375,9 +389,10 @@ public: return QString(); } + ClickHandlerPtr createOpenLink(); const ClickHandlerPtr &openLink() { if (!_openLink) { - _openLink = peerOpenClickHandler(this); + _openLink = createOpenLink(); } return _openLink; }