mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-10 16:59:55 +00:00
Allow to ban from actions log user context menu.
This commit is contained in:
parent
1a7353fb43
commit
0c43aabfec
@ -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<Window::Controller*> 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<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() {
|
||||
request(base::take(_preloadUpRequestId)).cancel();
|
||||
request(base::take(_preloadDownRequestId)).cancel();
|
||||
@ -374,6 +422,8 @@ QPoint InnerWidget::tooltipPos() const {
|
||||
|
||||
void InnerWidget::saveState(gsl::not_null<SectionMemento*> 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<SectionMemento*> 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<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() {
|
||||
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<PhotoClickHandler*>(_contextMenuLink.data());
|
||||
auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_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<PeerClickHandler*>(_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<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 ¤tRights) {
|
||||
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) {
|
||||
if (_menu) {
|
||||
e->accept();
|
||||
|
@ -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<void(FilterValue &&filter)> 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<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 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<MTPChannelAdminLogEvent> &events);
|
||||
|
||||
void toggleScrollDateShown();
|
||||
void repaintScrollDateCallback();
|
||||
@ -232,6 +235,9 @@ private:
|
||||
|
||||
FilterValue _filter;
|
||||
QString _searchQuery;
|
||||
std::vector<gsl::not_null<UserData*>> _admins;
|
||||
std::vector<gsl::not_null<UserData*>> _adminsCanEdit;
|
||||
base::lambda<void(FilterValue &&filter)> _showFilterCallback;
|
||||
|
||||
};
|
||||
|
||||
|
@ -250,7 +250,7 @@ void GenerateItems(gsl::not_null<History*> 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) {
|
||||
|
@ -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<ChannelData*> channel);
|
||||
@ -264,37 +261,10 @@ Widget::Widget(QWidget *parent, gsl::not_null<Window::Controller*> 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<FilterBox>(_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<Window::SectionMemento> Widget::createMemento() {
|
||||
|
||||
void Widget::saveState(gsl::not_null<SectionMemento*> memento) {
|
||||
memento->setScrollTop(_scroll->scrollTop());
|
||||
memento->setAdmins(std::move(_admins));
|
||||
_inner->saveState(memento);
|
||||
}
|
||||
|
||||
void Widget::restoreState(gsl::not_null<SectionMemento*> memento) {
|
||||
_inner->restoreState(memento);
|
||||
_admins = memento->takeAdmins();
|
||||
auto scrollTop = memento->getScrollTop();
|
||||
_scroll->scrollToY(scrollTop);
|
||||
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||
|
@ -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<Window::Controller*> controller, gsl::not_null<ChannelData*> channel);
|
||||
|
||||
@ -128,7 +128,6 @@ private:
|
||||
object_ptr<FixedBar> _fixedBar;
|
||||
object_ptr<Ui::PlainShadow> _fixedBarShadow;
|
||||
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) {
|
||||
_admins = std::move(admins);
|
||||
}
|
||||
void setAdminsCanEdit(std::vector<gsl::not_null<UserData*>> admins) {
|
||||
_adminsCanEdit = std::move(admins);
|
||||
}
|
||||
std::vector<gsl::not_null<UserData*>> takeAdmins() {
|
||||
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) {
|
||||
_items = std::move(items);
|
||||
@ -197,6 +202,7 @@ private:
|
||||
gsl::not_null<ChannelData*> _channel;
|
||||
int _scrollTop = 0;
|
||||
std::vector<gsl::not_null<UserData*>> _admins;
|
||||
std::vector<gsl::not_null<UserData*>> _adminsCanEdit;
|
||||
std::vector<HistoryItemOwned> _items;
|
||||
std::map<uint64, HistoryItem*> _itemsByIds;
|
||||
bool _upLoaded = false;
|
||||
|
@ -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<History*>
|
||||
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;
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ protected:
|
||||
return textcmdLink(1, _from->name);
|
||||
};
|
||||
ClickHandlerPtr fromLink() const {
|
||||
return peerOpenClickHandler(_from);
|
||||
return _from->createOpenLink();
|
||||
};
|
||||
|
||||
void removeMedia();
|
||||
|
@ -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<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)) {
|
||||
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<PeerClickHandler>(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<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() {
|
||||
static MsgId currentClientMsgId = StartClientMsgId;
|
||||
t_assert(currentClientMsgId < EndClientMsgId);
|
||||
|
@ -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<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 ChatData;
|
||||
@ -375,9 +389,10 @@ public:
|
||||
return QString();
|
||||
}
|
||||
|
||||
ClickHandlerPtr createOpenLink();
|
||||
const ClickHandlerPtr &openLink() {
|
||||
if (!_openLink) {
|
||||
_openLink = peerOpenClickHandler(this);
|
||||
_openLink = createOpenLink();
|
||||
}
|
||||
return _openLink;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user