Allow to ban from actions log user context menu.

This commit is contained in:
John Preston 2017-07-05 21:11:31 +03:00
parent 1a7353fb43
commit 0c43aabfec
9 changed files with 266 additions and 128 deletions

View File

@ -25,18 +25,23 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "history/history_message.h" #include "history/history_message.h"
#include "history/history_service_layout.h" #include "history/history_service_layout.h"
#include "history/history_admin_log_section.h" #include "history/history_admin_log_section.h"
#include "history/history_admin_log_filter.h"
#include "chat_helpers/message_field.h" #include "chat_helpers/message_field.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "apiwrap.h"
#include "window/window_controller.h" #include "window/window_controller.h"
#include "auth_session.h" #include "auth_session.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "core/file_utilities.h" #include "core/file_utilities.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "boxes/edit_participant_box.h"
namespace AdminLog { namespace AdminLog {
namespace { 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 kScrollDateHideTimeout = 1000;
constexpr auto kEventsFirstPage = 20; constexpr auto kEventsFirstPage = 20;
constexpr auto kEventsPerPage = 50; constexpr auto kEventsPerPage = 50;
@ -223,6 +228,8 @@ InnerWidget::InnerWidget(QWidget *parent, gsl::not_null<Window::Controller*> con
} }
}); });
updateEmptyText(); updateEmptyText();
requestAdmins();
} }
void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { 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<void(FilterValue &&filter)> callback) {
if (_admins.empty()) {
_showFilterCallback = std::move(callback);
} else {
Ui::show(Box<FilterBox>(_channel, _admins, _filter, std::move(callback)));
}
}
void InnerWidget::clearAndRequestLog() { void InnerWidget::clearAndRequestLog() {
request(base::take(_preloadUpRequestId)).cancel(); request(base::take(_preloadUpRequestId)).cancel();
request(base::take(_preloadDownRequestId)).cancel(); request(base::take(_preloadDownRequestId)).cancel();
@ -374,6 +422,8 @@ QPoint InnerWidget::tooltipPos() const {
void InnerWidget::saveState(gsl::not_null<SectionMemento*> memento) { void InnerWidget::saveState(gsl::not_null<SectionMemento*> memento) {
memento->setFilter(std::move(_filter)); memento->setFilter(std::move(_filter));
memento->setAdmins(std::move(_admins));
memento->setAdminsCanEdit(std::move(_adminsCanEdit));
memento->setSearchQuery(std::move(_searchQuery)); memento->setSearchQuery(std::move(_searchQuery));
if (!_filterChanged) { if (!_filterChanged) {
memento->setItems(std::move(_items), std::move(_itemsByIds), _upLoaded, _downLoaded); memento->setItems(std::move(_items), std::move(_itemsByIds), _upLoaded, _downLoaded);
@ -386,6 +436,8 @@ void InnerWidget::restoreState(gsl::not_null<SectionMemento*> memento) {
_items = memento->takeItems(); _items = memento->takeItems();
_itemsByIds = memento->takeItemsByIds(); _itemsByIds = memento->takeItemsByIds();
_idManager = memento->takeIdManager(); _idManager = memento->takeIdManager();
_admins = memento->takeAdmins();
_adminsCanEdit = memento->takeAdminsCanEdit();
_filter = memento->takeFilter(); _filter = memento->takeFilter();
_searchQuery = memento->takeSearchQuery(); _searchQuery = memento->takeSearchQuery();
_upLoaded = memento->upLoaded(); _upLoaded = memento->upLoaded();
@ -427,65 +479,9 @@ void InnerWidget::preloadMore(Direction direction) {
auto &results = result.c_channels_adminLogResults(); auto &results = result.c_channels_adminLogResults();
App::feedUsers(results.vusers); App::feedUsers(results.vusers);
App::feedChats(results.vchats); App::feedChats(results.vchats);
if (!loadedFlag) {
if (loadedFlag) { addEvents(direction, results.vevents.v);
return;
} }
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) { }).fail([this, &requestId, &loadedFlag](const RPCError &error) {
requestId = 0; requestId = 0;
loadedFlag = true; loadedFlag = true;
@ -493,6 +489,61 @@ void InnerWidget::preloadMore(Direction direction) {
}).send(); }).send();
} }
void InnerWidget::addEvents(Direction direction, const QVector<MTPChannelAdminLogEvent> &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<HistoryItemOwned>();
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() { void InnerWidget::updateMinMaxIds() {
if (_itemsByIds.empty() || _filterChanged) { if (_itemsByIds.empty() || _filterChanged) {
_maxId = _minId = 0; _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(); updateSize();
} }
@ -731,9 +799,10 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
auto item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem(); auto item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem();
auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(_contextMenuLink.data()); auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(_contextMenuLink.data());
auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.data()); auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.data());
bool lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideo() : false; auto lnkPeer = dynamic_cast<PeerClickHandler*>(_contextMenuLink.data());
bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false; auto lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideo() : false;
bool lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false; auto lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false;
auto lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false;
if (lnkPhoto || lnkDocument) { if (lnkPhoto || lnkDocument) {
if (isUponSelected > 0) { if (isUponSelected > 0) {
_menu->addAction(lang(lng_context_copy_selected), [this] { copySelectedText(); })->setEnabled(true); _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()) { if (App::hoveredLinkItem()) {
App::contextItem(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? } else { // maybe cursor on some text history item?
bool canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg()); bool canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg());
bool canForward = item && item->canForward(); bool canForward = item && item->canForward();
@ -934,6 +1007,71 @@ void InnerWidget::setToClipboard(const TextWithEntities &forClipboard, QClipboar
} }
} }
void InnerWidget::suggestRestrictUser(gsl::not_null<UserData*> 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 &currentRights) {
auto weak = QPointer<InnerWidget>(this);
auto box = std::make_shared<QPointer<EditRestrictedBox>>();
*box = Ui::show(Box<EditRestrictedBox>(_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<UserData*> user, const MTPChannelBannedRights &rights) {
auto weak = QPointer<InnerWidget>(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<UserData*> 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) { void InnerWidget::mousePressEvent(QMouseEvent *e) {
if (_menu) { if (_menu) {
e->accept(); e->accept();

View File

@ -66,10 +66,8 @@ public:
// Empty "flags" means all events. // Empty "flags" means all events.
void applyFilter(FilterValue &&value); void applyFilter(FilterValue &&value);
FilterValue filter() const {
return _filter;
}
void applySearch(const QString &query); void applySearch(const QString &query);
void showFilter(base::lambda<void(FilterValue &&filter)> callback);
// AbstractTooltipShower interface // AbstractTooltipShower interface
QString tooltipText() const override; QString tooltipText() const override;
@ -131,17 +129,22 @@ private:
void copySelectedText(); void copySelectedText();
TextWithEntities getSelectedText() const; TextWithEntities getSelectedText() const;
void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard); void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard);
void suggestRestrictUser(gsl::not_null<UserData*> user);
void restrictUser(gsl::not_null<UserData*> user, const MTPChannelBannedRights &rights);
void restrictUserDone(gsl::not_null<UserData*> user, const MTPChannelBannedRights &rights);
void requestAdmins();
void checkPreloadMore(); void checkPreloadMore();
void updateVisibleTopItem(); void updateVisibleTopItem();
void preloadMore(Direction direction); void preloadMore(Direction direction);
void itemsAdded(Direction direction); void itemsAdded(Direction direction, int addedCount);
void updateSize(); void updateSize();
void updateMinMaxIds(); void updateMinMaxIds();
void updateEmptyText(); void updateEmptyText();
void paintEmpty(Painter &p); void paintEmpty(Painter &p);
void clearAfterFilterChange(); void clearAfterFilterChange();
void clearAndRequestLog(); void clearAndRequestLog();
void addEvents(Direction direction, const QVector<MTPChannelAdminLogEvent> &events);
void toggleScrollDateShown(); void toggleScrollDateShown();
void repaintScrollDateCallback(); void repaintScrollDateCallback();
@ -232,6 +235,9 @@ private:
FilterValue _filter; FilterValue _filter;
QString _searchQuery; QString _searchQuery;
std::vector<gsl::not_null<UserData*>> _admins;
std::vector<gsl::not_null<UserData*>> _adminsCanEdit;
base::lambda<void(FilterValue &&filter)> _showFilterCallback;
}; };

View File

@ -250,7 +250,7 @@ void GenerateItems(gsl::not_null<History*> history, LocalIdManager &idManager, c
using Flag = MTPDmessage::Flag; using Flag = MTPDmessage::Flag;
auto fromName = App::peerName(from); auto fromName = App::peerName(from);
auto fromLink = peerOpenClickHandler(from); auto fromLink = from->createOpenLink();
auto fromLinkText = textcmdLink(1, fromName); auto fromLinkText = textcmdLink(1, fromName);
auto addSimpleServiceMessage = [&](const QString &text, PhotoData *photo = nullptr) { auto addSimpleServiceMessage = [&](const QString &text, PhotoData *photo = nullptr) {

View File

@ -39,9 +39,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace AdminLog { 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 { class FixedBar final : public TWidget, private base::Subscriber {
public: public:
FixedBar(QWidget *parent, gsl::not_null<ChannelData*> channel); FixedBar(QWidget *parent, gsl::not_null<ChannelData*> channel);
@ -264,37 +261,10 @@ Widget::Widget(QWidget *parent, gsl::not_null<Window::Controller*> controller, g
} }
void Widget::showFilter() { void Widget::showFilter() {
if (_admins.empty()) { _inner->showFilter([this](FilterValue &&filter) {
request(MTPchannels_GetParticipants(_inner->channel()->inputChannel, MTP_channelParticipantsAdmins(), MTP_int(0), MTP_int(kMaxChannelAdmins))).done([this](const MTPchannels_ChannelParticipants &result) { applyFilter(std::move(filter));
Expects(result.type() == mtpc_channels_channelParticipants); Ui::hideLayer();
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<FilterBox>(_inner->channel(), _admins, _inner->filter(), [this](FilterValue &&filter) {
applyFilter(std::move(filter));
Ui::hideLayer();
}));
}
} }
void Widget::updateAdaptiveLayout() { void Widget::updateAdaptiveLayout() {
@ -350,13 +320,11 @@ std::unique_ptr<Window::SectionMemento> Widget::createMemento() {
void Widget::saveState(gsl::not_null<SectionMemento*> memento) { void Widget::saveState(gsl::not_null<SectionMemento*> memento) {
memento->setScrollTop(_scroll->scrollTop()); memento->setScrollTop(_scroll->scrollTop());
memento->setAdmins(std::move(_admins));
_inner->saveState(memento); _inner->saveState(memento);
} }
void Widget::restoreState(gsl::not_null<SectionMemento*> memento) { void Widget::restoreState(gsl::not_null<SectionMemento*> memento) {
_inner->restoreState(memento); _inner->restoreState(memento);
_admins = memento->takeAdmins();
auto scrollTop = memento->getScrollTop(); auto scrollTop = memento->getScrollTop();
_scroll->scrollToY(scrollTop); _scroll->scrollToY(scrollTop);
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());

View File

@ -80,7 +80,7 @@ private:
}; };
class Widget final : public Window::SectionWidget, private MTP::Sender { class Widget final : public Window::SectionWidget {
public: public:
Widget(QWidget *parent, gsl::not_null<Window::Controller*> controller, gsl::not_null<ChannelData*> channel); Widget(QWidget *parent, gsl::not_null<Window::Controller*> controller, gsl::not_null<ChannelData*> channel);
@ -128,7 +128,6 @@ private:
object_ptr<FixedBar> _fixedBar; object_ptr<FixedBar> _fixedBar;
object_ptr<Ui::PlainShadow> _fixedBarShadow; object_ptr<Ui::PlainShadow> _fixedBarShadow;
object_ptr<Ui::FlatButton> _whatIsThis; object_ptr<Ui::FlatButton> _whatIsThis;
std::vector<gsl::not_null<UserData*>> _admins;
}; };
@ -152,9 +151,15 @@ public:
void setAdmins(std::vector<gsl::not_null<UserData*>> admins) { void setAdmins(std::vector<gsl::not_null<UserData*>> admins) {
_admins = std::move(admins); _admins = std::move(admins);
} }
void setAdminsCanEdit(std::vector<gsl::not_null<UserData*>> admins) {
_adminsCanEdit = std::move(admins);
}
std::vector<gsl::not_null<UserData*>> takeAdmins() { std::vector<gsl::not_null<UserData*>> takeAdmins() {
return std::move(_admins); return std::move(_admins);
} }
std::vector<gsl::not_null<UserData*>> takeAdminsCanEdit() {
return std::move(_adminsCanEdit);
}
void setItems(std::vector<HistoryItemOwned> &&items, std::map<uint64, HistoryItem*> &&itemsByIds, bool upLoaded, bool downLoaded) { void setItems(std::vector<HistoryItemOwned> &&items, std::map<uint64, HistoryItem*> &&itemsByIds, bool upLoaded, bool downLoaded) {
_items = std::move(items); _items = std::move(items);
@ -197,6 +202,7 @@ private:
gsl::not_null<ChannelData*> _channel; gsl::not_null<ChannelData*> _channel;
int _scrollTop = 0; int _scrollTop = 0;
std::vector<gsl::not_null<UserData*>> _admins; std::vector<gsl::not_null<UserData*>> _admins;
std::vector<gsl::not_null<UserData*>> _adminsCanEdit;
std::vector<HistoryItemOwned> _items; std::vector<HistoryItemOwned> _items;
std::map<uint64, HistoryItem*> _itemsByIds; std::map<uint64, HistoryItem*> _itemsByIds;
bool _upLoaded = false; bool _upLoaded = false;

View File

@ -53,7 +53,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
result.text = lng_action_user_joined(lt_from, fromLinkText()); result.text = lng_action_user_joined(lt_from, fromLinkText());
} else { } else {
result.links.push_back(fromLink()); 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)); result.text = lng_action_add_user(lt_from, fromLinkText(), lt_user, textcmdLink(2, u->name));
} }
} else if (users.isEmpty()) { } else if (users.isEmpty()) {
@ -63,7 +63,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
result.links.push_back(fromLink()); result.links.push_back(fromLink());
for (auto i = 0, l = users.size(); i != l; ++i) { for (auto i = 0, l = users.size(); i != l; ++i) {
auto user = App::user(peerFromUser(users[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); auto linkText = textcmdLink(i + 2, user->name);
if (i == 0) { if (i == 0) {
@ -123,7 +123,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
} else { } else {
auto user = App::user(peerFromUser(action.vuser_id)); auto user = App::user(peerFromUser(action.vuser_id));
result.links.push_back(fromLink()); 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)); result.text = lng_action_kick_user(lt_from, fromLinkText(), lt_user, textcmdLink(2, user->name));
} }
return result; return result;
@ -687,7 +687,7 @@ HistoryJoined::PreparedText HistoryJoined::GenerateText(gsl::not_null<History*>
return { lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined) }; return { lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined) };
} }
auto result = PreparedText {}; 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)); result.text = (history->isMegagroup() ? lng_action_add_you_group : lng_action_add_you)(lt_from, textcmdLink(1, inviter->name));
return result; return result;
} }

View File

@ -115,7 +115,7 @@ protected:
return textcmdLink(1, _from->name); return textcmdLink(1, _from->name);
}; };
ClickHandlerPtr fromLink() const { ClickHandlerPtr fromLink() const {
return peerOpenClickHandler(_from); return _from->createOpenLink();
}; };
void removeMedia(); void removeMedia();

View File

@ -248,6 +248,23 @@ using UpdateFlag = Notify::PeerUpdate::Flag;
NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats; NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats;
NotifySettingsPtr globalNotifyAllPtr = UnknownNotifySettings, globalNotifyUsersPtr = UnknownNotifySettings, globalNotifyChatsPtr = UnknownNotifySettings; NotifySettingsPtr globalNotifyAllPtr = UnknownNotifySettings, globalNotifyUsersPtr = UnknownNotifySettings, globalNotifyChatsPtr = UnknownNotifySettings;
PeerClickHandler::PeerClickHandler(gsl::not_null<PeerData*> 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<InformBox>(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)) { PeerData::PeerData(const PeerId &id) : id(id), _colorIndex(peerColorIndex(id)) {
nameText.setText(st::msgNameStyle, QString(), _textNameOptions); nameText.setText(st::msgNameStyle, QString(), _textNameOptions);
_userpicEmpty.set(_colorIndex, QString()); _userpicEmpty.set(_colorIndex, QString());
@ -304,6 +321,10 @@ void PeerData::updateNameDelayed(const QString &newName, const QString &newNameO
Notify::peerUpdatedDelayed(update); Notify::peerUpdatedDelayed(update);
} }
ClickHandlerPtr PeerData::createOpenLink() {
return MakeShared<PeerClickHandler>(this);
}
void PeerData::setUserpic(ImagePtr userpic) { void PeerData::setUserpic(ImagePtr userpic) {
_userpic = userpic; _userpic = userpic;
if (!_userpic || !_userpic->loaded()) { if (!_userpic || !_userpic->loaded()) {
@ -2106,22 +2127,6 @@ GameData::GameData(const GameId &id, const uint64 &accessHash, const QString &sh
, document(document) { , document(document) {
} }
ClickHandlerPtr peerOpenClickHandler(PeerData *peer) {
return MakeShared<LambdaClickHandler>([peer] {
if (App::main()) {
if (peer && peer->isChannel() && App::main()->historyPeer() != peer) {
if (!peer->asChannel()->isPublic() && !peer->asChannel()->amIn()) {
Ui::show(Box<InformBox>(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() { MsgId clientMsgId() {
static MsgId currentClientMsgId = StartClientMsgId; static MsgId currentClientMsgId = StartClientMsgId;
t_assert(currentClientMsgId < EndClientMsgId); t_assert(currentClientMsgId < EndClientMsgId);

View File

@ -267,7 +267,21 @@ inline const QString &emptyUsername() {
return empty; return empty;
} }
ClickHandlerPtr peerOpenClickHandler(PeerData *peer); class PeerData;
class PeerClickHandler : public ClickHandler {
public:
PeerClickHandler(gsl::not_null<PeerData*> peer);
void onClick(Qt::MouseButton button) const override;
gsl::not_null<PeerData*> peer() const {
return _peer;
}
private:
gsl::not_null<PeerData*> _peer;
};
class UserData; class UserData;
class ChatData; class ChatData;
@ -375,9 +389,10 @@ public:
return QString(); return QString();
} }
ClickHandlerPtr createOpenLink();
const ClickHandlerPtr &openLink() { const ClickHandlerPtr &openLink() {
if (!_openLink) { if (!_openLink) {
_openLink = peerOpenClickHandler(this); _openLink = createOpenLink();
} }
return _openLink; return _openLink;
} }