Replace group admins ContactsBox with PeerListBox.

This commit is contained in:
John Preston 2017-08-14 15:48:11 +03:00
parent f7359093b4
commit 0880c01a20
14 changed files with 708 additions and 267 deletions

View File

@ -1805,4 +1805,112 @@ void ApiWrap::checkForUnreadMentions(const base::flat_set<MsgId> &possiblyReadMe
}
}
void ApiWrap::cancelEditChatAdmins(gsl::not_null<ChatData*> chat) {
_chatAdminsEnabledRequests.take(chat)
| requestCanceller();
_chatAdminsSaveRequests.take(chat)
| base::for_each_apply(requestCanceller());
_chatAdminsToSave.remove(chat);
}
void ApiWrap::editChatAdmins(
gsl::not_null<ChatData*> chat,
bool adminsEnabled,
base::flat_set<gsl::not_null<UserData*>> &&admins) {
cancelEditChatAdmins(chat);
if (adminsEnabled) {
_chatAdminsToSave.emplace(chat, std::move(admins));
}
auto requestId = request(MTPmessages_ToggleChatAdmins(chat->inputChat, MTP_bool(adminsEnabled))).done([this, chat](const MTPUpdates &updates) {
_chatAdminsEnabledRequests.remove(chat);
applyUpdates(updates);
saveChatAdmins(chat);
}).fail([this, chat](const RPCError &error) {
_chatAdminsEnabledRequests.remove(chat);
if (error.type() == qstr("CHAT_NOT_MODIFIED")) {
saveChatAdmins(chat);
}
}).send();
_chatAdminsEnabledRequests.emplace(chat, requestId);
}
void ApiWrap::saveChatAdmins(gsl::not_null<ChatData*> chat) {
if (!_chatAdminsToSave.contains(chat)) {
return;
}
auto requestId = request(MTPmessages_GetFullChat(chat->inputChat)).done([this, chat](const MTPmessages_ChatFull &result) {
_chatAdminsEnabledRequests.remove(chat);
processFullPeer(chat, result);
sendSaveChatAdminsRequests(chat);
}).fail([this, chat](const RPCError &error) {
_chatAdminsEnabledRequests.remove(chat);
_chatAdminsToSave.remove(chat);
}).send();
_chatAdminsEnabledRequests.emplace(chat, requestId);
}
void ApiWrap::sendSaveChatAdminsRequests(gsl::not_null<ChatData*> chat) {
auto editOne = [this, chat](gsl::not_null<UserData*> user, bool admin) {
auto requestId = request(MTPmessages_EditChatAdmin(
chat->inputChat,
user->inputUser,
MTP_bool(admin)))
.done([this, chat, user, admin](
const MTPBool &result,
mtpRequestId requestId) {
_chatAdminsSaveRequests[chat].remove(requestId);
if (_chatAdminsSaveRequests[chat].empty()) {
_chatAdminsSaveRequests.remove(chat);
Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged);
}
if (mtpIsTrue(result)) {
if (admin) {
if (chat->noParticipantInfo()) {
requestFullPeer(chat);
} else {
chat->admins.insert(user);
}
} else {
chat->admins.remove(user);
}
}
}).fail([this, chat](
const RPCError &error,
mtpRequestId requestId) {
_chatAdminsSaveRequests[chat].remove(requestId);
if (_chatAdminsSaveRequests[chat].empty()) {
_chatAdminsSaveRequests.remove(chat);
}
chat->invalidateParticipants();
if (error.type() == qstr("USER_RESTRICTED")) {
Ui::show(Box<InformBox>(lang(lng_cant_do_this)));
}
}).canWait(5).send();
_chatAdminsSaveRequests[chat].insert(requestId);
};
auto appointOne = [&](auto user) { editOne(user, true); };
auto removeOne = [&](auto user) { editOne(user, false); };
auto admins = _chatAdminsToSave.take(chat);
t_assert(!!admins);
auto toRemove = chat->admins;
auto toAppoint = std::vector<gsl::not_null<UserData*>>();
if (!admins->empty()) {
toAppoint.reserve(admins->size());
for (auto user : *admins) {
if (!toRemove.remove(user) && user->id != peerFromUser(chat->creator)) {
toAppoint.push_back(user);
}
}
}
base::for_each(toRemove, removeOne);
base::for_each(toAppoint, appointOne);
requestSendDelayed();
}
ApiWrap::~ApiWrap() = default;

View File

@ -103,6 +103,11 @@ public:
void preloadEnoughUnreadMentions(gsl::not_null<History*> history);
void checkForUnreadMentions(const base::flat_set<MsgId> &possiblyReadMentions, ChannelData *channel = nullptr);
void editChatAdmins(
gsl::not_null<ChatData*> chat,
bool adminsEnabled,
base::flat_set<gsl::not_null<UserData*>> &&admins);
~ApiWrap();
private:
@ -144,6 +149,10 @@ private:
void requestFeaturedStickers(TimeId now);
void requestSavedGifs(TimeId now);
void cancelEditChatAdmins(gsl::not_null<ChatData*> chat);
void saveChatAdmins(gsl::not_null<ChatData*> chat);
void sendSaveChatAdminsRequests(gsl::not_null<ChatData*> chat);
gsl::not_null<AuthSession*> _session;
mtpRequestId _changelogSubscription = 0;
@ -196,6 +205,10 @@ private:
base::flat_map<gsl::not_null<History*>, mtpRequestId> _unreadMentionsRequests;
base::flat_map<gsl::not_null<ChatData*>, mtpRequestId> _chatAdminsEnabledRequests;
base::flat_map<gsl::not_null<ChatData*>, base::flat_set<gsl::not_null<UserData*>>> _chatAdminsToSave;
base::flat_map<gsl::not_null<ChatData*>, base::flat_set<mtpRequestId>> _chatAdminsSaveRequests;
base::Observable<PeerData*> _fullPeerUpdated;
};

View File

@ -54,126 +54,6 @@ style::InputField CreateBioFieldStyle() {
return result;
}
base::flat_set<gsl::not_null<UserData*>> GetAlreadyInFromPeer(PeerData *peer) {
if (!peer) {
return {};
}
if (auto chat = peer->asChat()) {
auto participants = chat->participants.keys();
return { participants.cbegin(), participants.cend() };
} else if (auto channel = peer->asChannel()) {
if (channel->isMegagroup()) {
auto &participants = channel->mgInfo->lastParticipants;
return { participants.cbegin(), participants.cend() };
}
}
return {};
}
class AddParticipantsBoxController : public ContactsBoxController {
public:
AddParticipantsBoxController(PeerData *peer);
AddParticipantsBoxController(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn);
using ContactsBoxController::ContactsBoxController;
void rowClicked(gsl::not_null<PeerListRow*> row) override;
void itemDeselectedHook(gsl::not_null<PeerData*> peer) override;
protected:
void prepareViewHook() override;
std::unique_ptr<PeerListRow> createRow(gsl::not_null<UserData*> user) override;
private:
int alreadyInCount() const;
bool isAlreadyIn(gsl::not_null<UserData*> user) const;
int fullCount() const;
void updateTitle();
PeerData *_peer = nullptr;
base::flat_set<gsl::not_null<UserData*>> _alreadyIn;
};
AddParticipantsBoxController::AddParticipantsBoxController(PeerData *peer)
: ContactsBoxController(std::make_unique<PeerListGlobalSearchController>())
, _peer(peer)
, _alreadyIn(GetAlreadyInFromPeer(peer)) {
}
AddParticipantsBoxController::AddParticipantsBoxController(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn)
: ContactsBoxController(std::make_unique<PeerListGlobalSearchController>())
, _peer(channel)
, _alreadyIn(std::move(alreadyIn)) {
}
void AddParticipantsBoxController::rowClicked(gsl::not_null<PeerListRow*> row) {
auto count = fullCount();
auto limit = (_peer && _peer->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax();
if (count < limit || row->checked()) {
delegate()->peerListSetRowChecked(row, !row->checked());
updateTitle();
} else if (auto channel = _peer ? _peer->asChannel() : nullptr) {
if (!_peer->isMegagroup()) {
Ui::show(Box<MaxInviteBox>(_peer->asChannel()), KeepOtherLayers);
}
} else if (count >= Global::ChatSizeMax() && count < Global::MegagroupSizeMax()) {
Ui::show(Box<InformBox>(lng_profile_add_more_after_upgrade(lt_count, Global::MegagroupSizeMax())), KeepOtherLayers);
}
}
void AddParticipantsBoxController::itemDeselectedHook(gsl::not_null<PeerData*> peer) {
updateTitle();
}
void AddParticipantsBoxController::prepareViewHook() {
updateTitle();
}
int AddParticipantsBoxController::alreadyInCount() const {
return _alreadyIn.empty() ? 1 : _alreadyIn.size(); // self
}
bool AddParticipantsBoxController::isAlreadyIn(gsl::not_null<UserData*> user) const {
if (!_peer) {
return false;
}
if (auto chat = _peer->asChat()) {
return chat->participants.contains(user);
} else if (auto channel = _peer->asChannel()) {
return _alreadyIn.contains(user)
|| (channel->isMegagroup() && channel->mgInfo->lastParticipants.contains(user));
}
Unexpected("User in AddParticipantsBoxController::isAlreadyIn");
}
int AddParticipantsBoxController::fullCount() const {
return alreadyInCount() + delegate()->peerListSelectedRowsCount();
}
std::unique_ptr<PeerListRow> AddParticipantsBoxController::createRow(gsl::not_null<UserData*> user) {
if (user->isSelf()) {
return nullptr;
}
auto result = std::make_unique<PeerListRow>(user);
if (isAlreadyIn(user)) {
result->setDisabledState(PeerListRow::State::DisabledChecked);
}
return result;
}
void AddParticipantsBoxController::updateTitle() {
auto additional = (_peer && _peer->isChannel() && !_peer->isMegagroup())
? QString() :
QString("%1 / %2").arg(fullCount()).arg(Global::MegagroupSizeMax());
delegate()->peerListSetTitle(langFactory(lng_profile_add_participant));
delegate()->peerListSetAdditionalTitle([additional] { return additional; });
}
} // namespace
QString PeerFloodErrorText(PeerFloodType type) {
@ -186,71 +66,6 @@ QString PeerFloodErrorText(PeerFloodType type) {
return lng_cant_send_to_not_contact(lt_more_info, link);
}
void ShowAddContactsToChatBox(gsl::not_null<ChatData*> chat) {
auto initBox = [chat](gsl::not_null<PeerListBox*> box) {
box->addButton(langFactory(lng_participant_invite), [box, chat] {
auto rows = box->peerListCollectSelectedRows();
if (!rows.empty()) {
auto users = std::vector<gsl::not_null<UserData*>>();
for (auto peer : rows) {
auto user = peer->asUser();
t_assert(user != nullptr);
t_assert(!user->isSelf());
users.push_back(peer->asUser());
}
App::main()->addParticipants(chat, users);
Ui::showPeerHistory(chat, ShowAtTheEndMsgId);
}
});
box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); });
};
Ui::show(Box<PeerListBox>(std::make_unique<AddParticipantsBoxController>(chat), std::move(initBox)));
}
void ShowAddContactsToChannelBox(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn,
bool justCreated) {
auto initBox = [channel, justCreated](gsl::not_null<PeerListBox*> box) {
auto subscription = std::make_shared<base::Subscription>();
box->addButton(langFactory(lng_participant_invite), [box, channel, subscription] {
auto rows = box->peerListCollectSelectedRows();
if (!rows.empty()) {
auto users = std::vector<gsl::not_null<UserData*>>();
for (auto peer : rows) {
auto user = peer->asUser();
t_assert(user != nullptr);
t_assert(!user->isSelf());
users.push_back(peer->asUser());
}
App::main()->addParticipants(channel, users);
if (channel->isMegagroup()) {
Ui::showPeerHistory(channel, ShowAtTheEndMsgId);
} else {
box->closeBox();
}
}
});
box->addButton(langFactory(justCreated ? lng_create_group_skip : lng_cancel), [box] { box->closeBox(); });
if (justCreated) {
*subscription = box->boxClosing.add_subscription([channel] {
Ui::showPeerHistory(channel, ShowAtTheEndMsgId);
});
}
};
Ui::show(Box<PeerListBox>(std::make_unique<AddParticipantsBoxController>(channel, std::move(alreadyIn)), std::move(initBox)));
}
void ShowAddContactsToChannelBox(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn) {
ShowAddContactsToChannelBox(channel, std::move(alreadyIn), false);
}
void ShowAddContactsToChannelBox(gsl::not_null<ChannelData*> channel) {
ShowAddContactsToChannelBox(channel, {}, true);
}
class RevokePublicLinkBox::Inner : public TWidget, private MTP::Sender {
public:
Inner(QWidget *parent, base::lambda<void()> revokeCallback);
@ -596,9 +411,9 @@ void GroupInfoBox::createGroup(gsl::not_null<PeerListBox*> selectUsersBox, const
| [](auto updates) -> base::optional<const QVector<MTPChat>*> {
switch (updates->type()) {
case mtpc_updates:
return &updates->c_updates().vchats.v;
return &updates->c_updates().vchats.v;
case mtpc_updatesCombined:
return &updates->c_updatesCombined().vchats.v;
return &updates->c_updatesCombined().vchats.v;
}
LOG(("API Error: unexpected update cons %1 (GroupInfoBox::creationDone)").arg(updates->type()));
return base::none;
@ -675,9 +490,9 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
| [](auto updates) -> base::optional<const QVector<MTPChat>*> {
switch (updates->type()) {
case mtpc_updates:
return &updates->c_updates().vchats.v;
return &updates->c_updates().vchats.v;
case mtpc_updatesCombined:
return &updates->c_updatesCombined().vchats.v;
return &updates->c_updatesCombined().vchats.v;
}
LOG(("API Error: unexpected update cons %1 (GroupInfoBox::createChannel)").arg(updates->type()));
return base::none;
@ -779,7 +594,7 @@ void SetupChannelBox::prepare() {
}));
subscribe(boxClosing, [this] {
if (!_existing) {
ShowAddContactsToChannelBox(_channel);
AddParticipantsBoxController::Start(_channel);
}
});

View File

@ -48,11 +48,6 @@ enum class PeerFloodType {
};
QString PeerFloodErrorText(PeerFloodType type);
void ShowAddContactsToChatBox(gsl::not_null<ChatData*> chat);
void ShowAddContactsToChannelBox(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn);
class AddContactBox : public BoxContent, public RPCSender {
Q_OBJECT

View File

@ -39,11 +39,26 @@ PeerListBox::PeerListBox(QWidget*, std::unique_ptr<PeerListController> controlle
Expects(_controller != nullptr);
}
object_ptr<Ui::WidgetSlideWrap<Ui::MultiSelect>> PeerListBox::createMultiSelect() {
void PeerListBox::createMultiSelect() {
Expects(_select == nullptr);
auto entity = object_ptr<Ui::MultiSelect>(this, st::contactsMultiSelect, langFactory(lng_participant_filter));
auto margins = style::margins(0, 0, 0, 0);
auto callback = [this] { updateScrollSkips(); };
return object_ptr<Ui::WidgetSlideWrap<Ui::MultiSelect>>(this, std::move(entity), margins, std::move(callback));
_select.create(this, std::move(entity), margins, std::move(callback));
_select->entity()->setSubmittedCallback([this](bool chtrlShiftEnter) { _inner->submitted(); });
_select->entity()->setQueryChangedCallback([this](const QString &query) { searchQueryChanged(query); });
_select->entity()->setItemRemovedCallback([this](uint64 itemId) {
if (auto peer = App::peerLoaded(itemId)) {
if (auto row = peerListFindRow(peer->id)) {
_inner->changeCheckState(row, false, PeerListRow::SetStyle::Animated);
update();
}
_controller->itemDeselectedHook(peer);
}
});
_select->resizeToWidth(st::boxWideWidth);
_select->moveToLeft(0, 0);
}
int PeerListBox::getTopScrollSkip() const {
@ -55,7 +70,12 @@ int PeerListBox::getTopScrollSkip() const {
}
void PeerListBox::updateScrollSkips() {
setInnerTopSkip(getTopScrollSkip(), true);
// If we show / hide the search field scroll top is fixed.
// If we resize search field by bubbles scroll bottom is fixed.
setInnerTopSkip(getTopScrollSkip(), _scrollBottomFixed);
if (!_select->animating()) {
_scrollBottomFixed = true;
}
}
void PeerListBox::prepare() {
@ -66,6 +86,7 @@ void PeerListBox::prepare() {
setDimensions(st::boxWideWidth, st::boxMaxListHeight);
if (_select) {
_select->finishAnimation();
_scrollBottomFixed = true;
onScrollToY(0);
}
@ -107,7 +128,7 @@ void PeerListBox::resizeEvent(QResizeEvent *e) {
updateScrollSkips();
}
_inner->resize(width(), _inner->height());
_inner->resizeToWidth(width());
}
void PeerListBox::paintEvent(QPaintEvent *e) {
@ -118,7 +139,7 @@ void PeerListBox::paintEvent(QPaintEvent *e) {
}
void PeerListBox::setInnerFocus() {
if (!_select || _select->isHidden()) {
if (!_select || _select->isHiddenOrHiding()) {
_inner->setFocus();
} else {
_select->entity()->setInnerFocus();
@ -205,26 +226,21 @@ void PeerListBox::peerListSetSearchNoResults(object_ptr<Ui::FlatLabel> noResults
_inner->setSearchNoResults(std::move(noResults));
}
void PeerListBox::peerListSetAboveWidget(object_ptr<TWidget> aboveWidget) {
_inner->setAboveWidget(std::move(aboveWidget));
}
void PeerListBox::peerListSetSearchMode(PeerListSearchMode mode) {
_inner->setSearchMode(mode);
if (mode != PeerListSearchMode::Disabled && !_select) {
_select = createMultiSelect();
_select->entity()->setSubmittedCallback([this](bool chtrlShiftEnter) { _inner->submitted(); });
_select->entity()->setQueryChangedCallback([this](const QString &query) { searchQueryChanged(query); });
_select->entity()->setItemRemovedCallback([this](uint64 itemId) {
if (auto peer = App::peerLoaded(itemId)) {
if (auto row = peerListFindRow(peer->id)) {
_inner->changeCheckState(row, false, PeerListRow::SetStyle::Animated);
update();
}
_controller->itemDeselectedHook(peer);
}
});
_select->resizeToWidth(st::boxWideWidth);
_select->moveToLeft(0, 0);
auto selectVisible = (mode != PeerListSearchMode::Disabled);
if (selectVisible && !_select) {
createMultiSelect();
_select->toggleFast(!selectVisible);
}
if (_select) {
_select->toggleAnimated(mode != PeerListSearchMode::Disabled);
_select->toggleAnimated(selectVisible);
_scrollBottomFixed = false;
setInnerFocus();
}
}
@ -298,7 +314,10 @@ void PeerListController::setSearchNoResultsText(const QString &text) {
}
void PeerListBox::addSelectItem(gsl::not_null<PeerData*> peer, PeerListRow::SetStyle style) {
Expects(_select != nullptr);
if (!_select) {
createMultiSelect();
_select->toggleFast(false);
}
if (style == PeerListRow::SetStyle::Fast) {
_select->entity()->addItemInBunch(peer->id, peer->shortName(), st::activeButtonBg, PaintUserpicCallback(peer));
} else {
@ -312,8 +331,7 @@ void PeerListBox::peerListFinishSelectedRowsBunch() {
}
bool PeerListBox::peerListIsRowSelected(gsl::not_null<PeerData*> peer) {
Expects(_select != nullptr);
return _select->entity()->hasItem(peer->id);
return _select ? _select->entity()->hasItem(peer->id) : false;
}
int PeerListBox::peerListSelectedRowsCount() {
@ -544,21 +562,16 @@ void PeerListBox::Inner::addRowEntry(gsl::not_null<PeerListRow*> row) {
if (addingToSearchIndex()) {
addToSearchIndex(row);
}
if (_searchMode != PeerListSearchMode::Disabled) {
if (_controller->isRowSelected(row->peer())) {
t_assert(row->id() == row->peer()->id);
if (_controller->isRowSelected(row->peer())) {
changeCheckState(row, true, PeerListRow::SetStyle::Fast);
}
changeCheckState(row, true, PeerListRow::SetStyle::Fast);
}
}
void PeerListBox::Inner::invalidatePixmapsCache() {
for_const (auto &row, _rows) {
row->invalidatePixmapsCache();
}
for_const (auto &row, _searchRows) {
row->invalidatePixmapsCache();
}
auto invalidate = [](auto &&row) { row->invalidatePixmapsCache(); };
base::for_each(_rows, invalidate);
base::for_each(_searchRows, invalidate);
}
bool PeerListBox::Inner::addingToSearchIndex() const {
@ -710,6 +723,13 @@ void PeerListBox::Inner::setSearchNoResults(object_ptr<Ui::FlatLabel> noResults)
}
}
void PeerListBox::Inner::setAboveWidget(object_ptr<TWidget> aboveWidget) {
_aboveWidget = std::move(aboveWidget);
if (_aboveWidget) {
_aboveWidget->setParent(this);
}
}
int PeerListBox::Inner::labelHeight() const {
auto computeLabelHeight = [](auto &label) {
if (!label) {
@ -730,20 +750,7 @@ int PeerListBox::Inner::labelHeight() const {
}
void PeerListBox::Inner::refreshRows() {
auto labelTop = st::membersMarginTop + qMax(1, shownRowsCount()) * _rowHeight;
resize(width(), labelTop + labelHeight() + st::membersMarginBottom);
if (_description) {
_description->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top());
_description->setVisible(!showingSearch());
}
if (_searchNoResults) {
_searchNoResults->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top());
_searchNoResults->setVisible(showingSearch() && _filterResults.empty() && !_controller->isSearchLoading());
}
if (_searchLoading) {
_searchLoading->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top());
_searchLoading->setVisible(showingSearch() && _filterResults.empty() && _controller->isSearchLoading());
}
resizeToWidth(st::boxWideWidth);
if (_visibleBottom > 0) {
checkScrollForPreload();
}
@ -781,10 +788,11 @@ void PeerListBox::Inner::paintEvent(QPaintEvent *e) {
p.fillRect(r, st::contactsBg);
auto rowsTopCached = rowsTop();
auto ms = getms();
auto yFrom = r.y() - st::membersMarginTop;
auto yTo = r.y() + r.height() - st::membersMarginTop;
p.translate(0, st::membersMarginTop);
auto yFrom = r.y() - rowsTopCached;
auto yTo = r.y() + r.height() - rowsTopCached;
p.translate(0, rowsTopCached);
auto count = shownRowsCount();
if (count > 0) {
auto from = floorclamp(yFrom, _rowHeight, 0, count);
@ -797,6 +805,34 @@ void PeerListBox::Inner::paintEvent(QPaintEvent *e) {
}
}
int PeerListBox::Inner::resizeGetHeight(int newWidth) {
_aboveHeight = 0;
if (_aboveWidget) {
_aboveWidget->resizeToWidth(newWidth);
_aboveWidget->moveToLeft(0, 0, newWidth);
if (showingSearch()) {
_aboveWidget->hide();
} else {
_aboveWidget->show();
_aboveHeight = _aboveWidget->height();
}
}
auto labelTop = rowsTop() + qMax(1, shownRowsCount()) * _rowHeight;
if (_description) {
_description->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top(), newWidth);
_description->setVisible(!showingSearch());
}
if (_searchNoResults) {
_searchNoResults->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top(), newWidth);
_searchNoResults->setVisible(showingSearch() && _filterResults.empty() && !_controller->isSearchLoading());
}
if (_searchLoading) {
_searchLoading->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top(), newWidth);
_searchLoading->setVisible(showingSearch() && _filterResults.empty() && _controller->isSearchLoading());
}
return labelTop + labelHeight() + st::membersMarginBottom;
}
void PeerListBox::Inner::enterEventHook(QEvent *e) {
setMouseTracking(true);
}
@ -1126,11 +1162,10 @@ void PeerListBox::Inner::restoreSelection() {
void PeerListBox::Inner::updateSelection() {
if (!_mouseSelection) return;
auto rowsTop = st::membersMarginTop;
auto point = mapFromGlobal(_lastMousePosition);
auto in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePosition));
auto selected = Selected();
auto rowsPointY = point.y() - rowsTop;
auto rowsPointY = point.y() - rowsTop();
selected.index.value = (in && rowsPointY >= 0 && rowsPointY < shownRowsCount() * _rowHeight) ? (rowsPointY / _rowHeight) : -1;
if (selected.index.value >= 0) {
auto row = getRow(selected.index);
@ -1162,9 +1197,13 @@ void PeerListBox::Inner::peerUpdated(PeerData *peer) {
update();
}
int PeerListBox::Inner::rowsTop() const {
return _aboveHeight + st::membersMarginTop;
}
int PeerListBox::Inner::getRowTop(RowIndex index) const {
if (index.value >= 0) {
return st::membersMarginTop + index.value * _rowHeight;
return rowsTop() + index.value * _rowHeight;
}
return -1;
}

View File

@ -185,6 +185,7 @@ public:
virtual void peerListSetDescription(object_ptr<Ui::FlatLabel> description) = 0;
virtual void peerListSetSearchLoading(object_ptr<Ui::FlatLabel> loading) = 0;
virtual void peerListSetSearchNoResults(object_ptr<Ui::FlatLabel> noResults) = 0;
virtual void peerListSetAboveWidget(object_ptr<TWidget> aboveWidget) = 0;
virtual void peerListSetSearchMode(PeerListSearchMode mode) = 0;
virtual void peerListAppendRow(std::unique_ptr<PeerListRow> row) = 0;
virtual void peerListAppendSearchRow(std::unique_ptr<PeerListRow> row) = 0;
@ -331,6 +332,7 @@ public:
void peerListSetDescription(object_ptr<Ui::FlatLabel> description) override;
void peerListSetSearchLoading(object_ptr<Ui::FlatLabel> loading) override;
void peerListSetSearchNoResults(object_ptr<Ui::FlatLabel> noResults) override;
void peerListSetAboveWidget(object_ptr<TWidget> aboveWidget) override;
void peerListSetSearchMode(PeerListSearchMode mode) override;
void peerListAppendRow(std::unique_ptr<PeerListRow> row) override;
void peerListAppendSearchRow(std::unique_ptr<PeerListRow> row) override;
@ -367,7 +369,7 @@ private:
void peerListFinishSelectedRowsBunch() override;
void addSelectItem(gsl::not_null<PeerData*> peer, PeerListRow::SetStyle style);
object_ptr<Ui::WidgetSlideWrap<Ui::MultiSelect>> createMultiSelect();
void createMultiSelect();
int getTopScrollSkip() const;
void updateScrollSkips();
void searchQueryChanged(const QString &query);
@ -379,6 +381,7 @@ private:
std::unique_ptr<PeerListController> _controller;
base::lambda<void(PeerListBox*)> _init;
bool _scrollBottomFixed = true;
};
@ -416,6 +419,7 @@ public:
void setDescription(object_ptr<Ui::FlatLabel> description);
void setSearchLoading(object_ptr<Ui::FlatLabel> loading);
void setSearchNoResults(object_ptr<Ui::FlatLabel> noResults);
void setAboveWidget(object_ptr<TWidget> aboveWidget);
void refreshRows();
void setSearchMode(PeerListSearchMode mode);
@ -438,6 +442,8 @@ public slots:
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
protected:
int resizeGetHeight(int newWidth) override;
void paintEvent(QPaintEvent *e) override;
void enterEventHook(QEvent *e) override;
void leaveEventHook(QEvent *e) override;
@ -515,6 +521,7 @@ private:
template <typename Callback>
bool enumerateShownRows(int from, int to, Callback callback);
int rowsTop() const;
int labelHeight() const;
void clearSearchRows();
@ -540,6 +547,8 @@ private:
QString _mentionHighlight;
std::vector<gsl::not_null<PeerListRow*>> _filterResults;
int _aboveHeight = 0;
object_ptr<TWidget> _aboveWidget = { nullptr };
object_ptr<Ui::FlatLabel> _description = { nullptr };
object_ptr<Ui::FlatLabel> _searchNoResults = { nullptr };
object_ptr<Ui::FlatLabel> _searchLoading = { nullptr };

View File

@ -21,11 +21,65 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "boxes/peer_list_controllers.h"
#include "styles/style_boxes.h"
#include "styles/style_profile.h"
#include "boxes/confirm_box.h"
#include "observer_peer.h"
#include "ui/widgets/checkbox.h"
#include "auth_session.h"
#include "apiwrap.h"
#include "mainwidget.h"
#include "lang/lang_keys.h"
#include "dialogs/dialogs_indexed_list.h"
namespace {
base::flat_set<gsl::not_null<UserData*>> GetAlreadyInFromPeer(PeerData *peer) {
if (!peer) {
return {};
}
if (auto chat = peer->asChat()) {
auto participants = chat->participants.keys();
return { participants.cbegin(), participants.cend() };
} else if (auto channel = peer->asChannel()) {
if (channel->isMegagroup()) {
auto &participants = channel->mgInfo->lastParticipants;
return { participants.cbegin(), participants.cend() };
}
}
return {};
}
} // namespace
class EditChatAdminsBoxController::LabeledCheckbox : public TWidget, private base::Subscriber {
public:
LabeledCheckbox(QWidget *parent, const QString &text, bool checked = false, const style::Checkbox &st = st::defaultCheckbox, const style::Check &checkSt = st::defaultCheck);
base::Observable<bool> checkedChanged;
bool checked() const {
return _checkbox->checked();
}
void setLabelText(
bool checked,
const style::TextStyle &st,
const QString &text,
const TextParseOptions &options = _defaultOptions,
int minResizeWidth = QFIXED_MAX);
protected:
int resizeGetHeight(int newWidth) override;
void paintEvent(QPaintEvent *e) override;
private:
object_ptr<Ui::Checkbox> _checkbox;
Text _labelUnchecked;
Text _labelChecked;
int _labelWidth = 0;
};
void PeerListRowWithLink::setActionLink(const QString &action) {
_action = action;
refreshActionLink();
@ -268,3 +322,337 @@ bool ContactsBoxController::appendRow(gsl::not_null<UserData*> user) {
std::unique_ptr<PeerListRow> ContactsBoxController::createRow(gsl::not_null<UserData*> user) {
return std::make_unique<PeerListRow>(user);
}
AddParticipantsBoxController::AddParticipantsBoxController(PeerData *peer)
: ContactsBoxController(std::make_unique<PeerListGlobalSearchController>())
, _peer(peer)
, _alreadyIn(GetAlreadyInFromPeer(peer)) {
}
AddParticipantsBoxController::AddParticipantsBoxController(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn)
: ContactsBoxController(std::make_unique<PeerListGlobalSearchController>())
, _peer(channel)
, _alreadyIn(std::move(alreadyIn)) {
}
void AddParticipantsBoxController::rowClicked(gsl::not_null<PeerListRow*> row) {
auto count = fullCount();
auto limit = (_peer && _peer->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax();
if (count < limit || row->checked()) {
delegate()->peerListSetRowChecked(row, !row->checked());
updateTitle();
} else if (auto channel = _peer ? _peer->asChannel() : nullptr) {
if (!_peer->isMegagroup()) {
Ui::show(Box<MaxInviteBox>(_peer->asChannel()), KeepOtherLayers);
}
} else if (count >= Global::ChatSizeMax() && count < Global::MegagroupSizeMax()) {
Ui::show(Box<InformBox>(lng_profile_add_more_after_upgrade(lt_count, Global::MegagroupSizeMax())), KeepOtherLayers);
}
}
void AddParticipantsBoxController::itemDeselectedHook(gsl::not_null<PeerData*> peer) {
updateTitle();
}
void AddParticipantsBoxController::prepareViewHook() {
updateTitle();
}
int AddParticipantsBoxController::alreadyInCount() const {
if (!_peer) {
return 1; // self
}
if (auto chat = _peer->asChat()) {
return qMax(chat->count, 1);
} else if (auto channel = _peer->asChannel()) {
return qMax(channel->membersCount(), int(_alreadyIn.size()));
}
Unexpected("User in AddParticipantsBoxController::alreadyInCount");
}
bool AddParticipantsBoxController::isAlreadyIn(gsl::not_null<UserData*> user) const {
if (!_peer) {
return false;
}
if (auto chat = _peer->asChat()) {
return chat->participants.contains(user);
} else if (auto channel = _peer->asChannel()) {
return _alreadyIn.contains(user)
|| (channel->isMegagroup() && channel->mgInfo->lastParticipants.contains(user));
}
Unexpected("User in AddParticipantsBoxController::isAlreadyIn");
}
int AddParticipantsBoxController::fullCount() const {
return alreadyInCount() + delegate()->peerListSelectedRowsCount();
}
std::unique_ptr<PeerListRow> AddParticipantsBoxController::createRow(gsl::not_null<UserData*> user) {
if (user->isSelf()) {
return nullptr;
}
auto result = std::make_unique<PeerListRow>(user);
if (isAlreadyIn(user)) {
result->setDisabledState(PeerListRow::State::DisabledChecked);
}
return result;
}
void AddParticipantsBoxController::updateTitle() {
auto additional = (_peer && _peer->isChannel() && !_peer->isMegagroup())
? QString() :
QString("%1 / %2").arg(fullCount()).arg(Global::MegagroupSizeMax());
delegate()->peerListSetTitle(langFactory(lng_profile_add_participant));
delegate()->peerListSetAdditionalTitle([additional] { return additional; });
}
void AddParticipantsBoxController::Start(gsl::not_null<ChatData*> chat) {
auto initBox = [chat](gsl::not_null<PeerListBox*> box) {
box->addButton(langFactory(lng_participant_invite), [box, chat] {
auto rows = box->peerListCollectSelectedRows();
if (!rows.empty()) {
auto users = std::vector<gsl::not_null<UserData*>>();
for (auto peer : rows) {
auto user = peer->asUser();
t_assert(user != nullptr);
t_assert(!user->isSelf());
users.push_back(peer->asUser());
}
App::main()->addParticipants(chat, users);
Ui::showPeerHistory(chat, ShowAtTheEndMsgId);
}
});
box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); });
};
Ui::show(Box<PeerListBox>(std::make_unique<AddParticipantsBoxController>(chat), std::move(initBox)));
}
void AddParticipantsBoxController::Start(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn,
bool justCreated) {
auto initBox = [channel, justCreated](gsl::not_null<PeerListBox*> box) {
auto subscription = std::make_shared<base::Subscription>();
box->addButton(langFactory(lng_participant_invite), [box, channel, subscription] {
auto rows = box->peerListCollectSelectedRows();
if (!rows.empty()) {
auto users = std::vector<gsl::not_null<UserData*>>();
for (auto peer : rows) {
auto user = peer->asUser();
t_assert(user != nullptr);
t_assert(!user->isSelf());
users.push_back(peer->asUser());
}
App::main()->addParticipants(channel, users);
if (channel->isMegagroup()) {
Ui::showPeerHistory(channel, ShowAtTheEndMsgId);
} else {
box->closeBox();
}
}
});
box->addButton(langFactory(justCreated ? lng_create_group_skip : lng_cancel), [box] { box->closeBox(); });
if (justCreated) {
*subscription = box->boxClosing.add_subscription([channel] {
Ui::showPeerHistory(channel, ShowAtTheEndMsgId);
});
}
};
Ui::show(Box<PeerListBox>(std::make_unique<AddParticipantsBoxController>(channel, std::move(alreadyIn)), std::move(initBox)));
}
void AddParticipantsBoxController::Start(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn) {
Start(channel, std::move(alreadyIn), false);
}
void AddParticipantsBoxController::Start(gsl::not_null<ChannelData*> channel) {
Start(channel, {}, true);
}
EditChatAdminsBoxController::LabeledCheckbox::LabeledCheckbox(
QWidget *parent,
const QString &text,
bool checked,
const style::Checkbox &st,
const style::Check &checkSt)
: TWidget(parent)
, _checkbox(this, text, checked, st, checkSt) {
subscribe(_checkbox->checkedChanged, [this](bool value) { checkedChanged.notify(value, true); });
}
void EditChatAdminsBoxController::LabeledCheckbox::setLabelText(
bool checked,
const style::TextStyle &st,
const QString &text,
const TextParseOptions &options,
int minResizeWidth) {
auto &label = (checked ? _labelChecked : _labelUnchecked);
label = Text(st, text, options, minResizeWidth);
}
int EditChatAdminsBoxController::LabeledCheckbox::resizeGetHeight(int newWidth) {
_labelWidth = newWidth - st::contactsPadding.left() - st::contactsPadding.right();
_checkbox->resizeToNaturalWidth(_labelWidth);
_checkbox->moveToLeft(st::contactsPadding.left(), st::contactsAllAdminsTop);
auto labelHeight = qMax(
_labelChecked.countHeight(_labelWidth),
_labelUnchecked.countHeight(_labelWidth));
return st::contactsAboutTop + labelHeight + st::contactsAboutBottom;
}
void EditChatAdminsBoxController::LabeledCheckbox::paintEvent(QPaintEvent *e) {
Painter p(this);
auto infoTop = _checkbox->bottomNoMargins() + st::contactsAllAdminsTop - st::lineWidth;
auto infoRect = rtlrect(0, infoTop, width(), height() - infoTop - st::contactsPadding.bottom(), width());
p.fillRect(infoRect, st::contactsAboutBg);
auto dividerFillTop = rtlrect(0, infoRect.y(), width(), st::profileDividerTop.height(), width());
st::profileDividerTop.fill(p, dividerFillTop);
auto dividerFillBottom = rtlrect(0, infoRect.y() + infoRect.height() - st::profileDividerBottom.height(), width(), st::profileDividerBottom.height(), width());
st::profileDividerBottom.fill(p, dividerFillBottom);
p.setPen(st::contactsAboutFg);
(checked() ? _labelChecked : _labelUnchecked).draw(p, st::contactsPadding.left(), st::contactsAboutTop, _labelWidth);
}
EditChatAdminsBoxController::EditChatAdminsBoxController(gsl::not_null<ChatData*> chat)
: PeerListController()
, _chat(chat) {
}
bool EditChatAdminsBoxController::allAreAdmins() const {
return _allAdmins->checked();
}
void EditChatAdminsBoxController::prepare() {
createAllAdminsCheckbox();
setSearchNoResultsText(lang(lng_blocked_list_not_found));
delegate()->peerListSetSearchMode(allAreAdmins() ? PeerListSearchMode::Disabled : PeerListSearchMode::Enabled);
delegate()->peerListSetTitle(langFactory(lng_channel_admins));
rebuildRows();
if (!delegate()->peerListFullRowsCount()) {
Auth().api().requestFullPeer(_chat);
_adminsUpdatedSubscription = subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(
Notify::PeerUpdate::Flag::AdminsChanged, [this](
const Notify::PeerUpdate &update) {
if (update.peer == _chat) {
rebuildRows();
if (delegate()->peerListFullRowsCount()) {
unsubscribe(_adminsUpdatedSubscription);
}
}
}));
}
subscribe(_allAdmins->checkedChanged, [this](bool checked) {
delegate()->peerListSetSearchMode(checked ? PeerListSearchMode::Disabled : PeerListSearchMode::Enabled);
for (auto i = 0, count = delegate()->peerListFullRowsCount(); i != count; ++i) {
auto row = delegate()->peerListRowAt(i);
auto user = row->peer()->asUser();
if (checked || user->id == peerFromUser(_chat->creator)) {
row->setDisabledState(PeerListRow::State::DisabledChecked);
} else {
row->setDisabledState(PeerListRow::State::Active);
}
}
});
}
void EditChatAdminsBoxController::createAllAdminsCheckbox() {
auto labelWidth = st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right();
auto checkbox = object_ptr<LabeledCheckbox>(nullptr, lang(lng_chat_all_members_admins), !_chat->adminsEnabled(), st::defaultBoxCheckbox);
checkbox->setLabelText(true, st::defaultTextStyle, lang(lng_chat_about_all_admins), _defaultOptions, labelWidth);
checkbox->setLabelText(false, st::defaultTextStyle, lang(lng_chat_about_admins), _defaultOptions, labelWidth);
_allAdmins = checkbox;
delegate()->peerListSetAboveWidget(std::move(checkbox));
}
void EditChatAdminsBoxController::rebuildRows() {
if (_chat->participants.empty()) {
return;
}
auto allAdmins = allAreAdmins();
auto admins = std::vector<gsl::not_null<UserData*>>();
auto others = admins;
admins.reserve(allAdmins ? _chat->participants.size() : _chat->admins.size());
others.reserve(_chat->participants.size());
for (auto i = _chat->participants.cbegin(), e = _chat->participants.cend(); i != e; ++i) {
if (i.key()->id == peerFromUser(_chat->creator)) continue;
if (_chat->admins.contains(i.key())) {
admins.push_back(i.key());
} else {
others.push_back(i.key());
}
}
if (!admins.empty()) {
delegate()->peerListAddSelectedRows(admins);
}
if (allAdmins) {
admins.insert(admins.end(), others.begin(), others.end());
others.clear();
}
auto sortByName = [](auto a, auto b) {
return (a->name.compare(b->name, Qt::CaseInsensitive) < 0);
};
std::sort(admins.begin(), admins.end(), sortByName);
std::sort(others.begin(), others.end(), sortByName);
auto addOne = [this](gsl::not_null<UserData*> user) {
if (auto row = createRow(user)) {
delegate()->peerListAppendRow(std::move(row));
}
};
if (auto creator = App::userLoaded(_chat->creator)) {
if (_chat->participants.contains(creator)) {
addOne(creator);
}
}
base::for_each(admins, addOne);
base::for_each(others, addOne);
delegate()->peerListRefreshRows();
}
std::unique_ptr<PeerListRow> EditChatAdminsBoxController::createRow(gsl::not_null<UserData*> user) {
auto result = std::make_unique<PeerListRow>(user);
if (allAreAdmins() || user->id == peerFromUser(_chat->creator)) {
result->setDisabledState(PeerListRow::State::DisabledChecked);
}
return result;
}
void EditChatAdminsBoxController::rowClicked(gsl::not_null<PeerListRow*> row) {
delegate()->peerListSetRowChecked(row, !row->checked());
}
void EditChatAdminsBoxController::Start(gsl::not_null<ChatData*> chat) {
auto controller = std::make_unique<EditChatAdminsBoxController>(chat);
auto initBox = [chat, controller = controller.get()](gsl::not_null<PeerListBox*> box) {
box->addButton(langFactory(lng_settings_save), [box, chat, controller] {
auto rows = box->peerListCollectSelectedRows();
if (!rows.empty()) {
auto users = std::vector<gsl::not_null<UserData*>>();
for (auto peer : rows) {
auto user = peer->asUser();
t_assert(user != nullptr);
t_assert(!user->isSelf());
users.push_back(peer->asUser());
}
Auth().api().editChatAdmins(chat, !controller->allAreAdmins(), { users.cbegin(), users.cend() });
box->closeBox();
}
});
box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); });
};
Ui::show(Box<PeerListBox>(std::move(controller), std::move(initBox)));
}

View File

@ -20,7 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "peer_list_box.h"
#include "boxes/peer_list_box.h"
#include "base/flat_set.h"
class PeerListRowWithLink : public PeerListRow {
public:
@ -117,3 +118,65 @@ private:
bool appendRow(gsl::not_null<UserData*> user);
};
class EditChatAdminsBoxController : public PeerListController, private base::Subscriber {
public:
static void Start(gsl::not_null<ChatData*> chat);
EditChatAdminsBoxController(gsl::not_null<ChatData*> chat);
bool allAreAdmins() const;
void prepare() override;
void rowClicked(gsl::not_null<PeerListRow*> row) override;
private:
void createAllAdminsCheckbox();
void rebuildRows();
std::unique_ptr<PeerListRow> createRow(gsl::not_null<UserData*> user);
gsl::not_null<ChatData*> _chat;
int _adminsUpdatedSubscription = 0;
class LabeledCheckbox;
QPointer<LabeledCheckbox> _allAdmins;
};
class AddParticipantsBoxController : public ContactsBoxController {
public:
static void Start(gsl::not_null<ChatData*> chat);
static void Start(gsl::not_null<ChannelData*> channel);
static void Start(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn);
AddParticipantsBoxController(PeerData *peer);
AddParticipantsBoxController(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn);
using ContactsBoxController::ContactsBoxController;
void rowClicked(gsl::not_null<PeerListRow*> row) override;
void itemDeselectedHook(gsl::not_null<PeerData*> peer) override;
protected:
void prepareViewHook() override;
std::unique_ptr<PeerListRow> createRow(gsl::not_null<UserData*> user) override;
private:
static void Start(
gsl::not_null<ChannelData*> channel,
base::flat_set<gsl::not_null<UserData*>> &&alreadyIn,
bool justCreated);
int alreadyInCount() const;
bool isAlreadyIn(gsl::not_null<UserData*> user) const;
int fullCount() const;
void updateTitle();
PeerData *_peer = nullptr;
base::flat_set<gsl::not_null<UserData*>> _alreadyIn;
};

View File

@ -69,7 +69,7 @@ class Sender {
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override {
auto handler = std::move(_handler);
_sender->requestHandled(requestId);
_sender->senderRequestHandled(requestId);
if (handler) {
auto result = Response();
@ -121,7 +121,7 @@ class Sender {
}
auto handler = std::move(_handler);
_sender->requestHandled(requestId);
_sender->senderRequestHandled(requestId);
if (handler) {
Policy::handle(std::move(handler), requestId, error);
@ -187,7 +187,7 @@ class Sender {
return _sender;
}
void registerRequest(mtpRequestId requestId) {
_sender->requestRegister(requestId);
_sender->senderRequestRegister(requestId);
}
private:
@ -270,7 +270,7 @@ public:
public:
void cancel() {
_sender->requestCancel(_requestId);
_sender->senderRequestCancel(_requestId);
}
private:
@ -284,6 +284,12 @@ public:
SentRequestWrap request(mtpRequestId requestId) noexcept WARN_UNUSED_RESULT;
decltype(auto) requestCanceller() noexcept WARN_UNUSED_RESULT {
return [this](mtpRequestId requestId) {
request(requestId).cancel();
};
}
void requestSendDelayed() {
MainInstance()->sendAnything();
}
@ -347,17 +353,17 @@ private:
friend class RequestWrap;
friend class SentRequestWrap;
void requestRegister(mtpRequestId requestId) {
void senderRequestRegister(mtpRequestId requestId) {
_requests.emplace(MainInstance(), requestId);
}
void requestHandled(mtpRequestId requestId) {
void senderRequestHandled(mtpRequestId requestId) {
auto it = _requests.find(requestId);
if (it != _requests.cend()) {
it->handled();
_requests.erase(it);
}
}
void requestCancel(mtpRequestId requestId) {
void senderRequestCancel(mtpRequestId requestId) {
auto it = _requests.find(requestId);
if (it != _requests.cend()) {
_requests.erase(it);

View File

@ -25,7 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_profile.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "boxes/contacts_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/confirm_box.h"
#include "observer_peer.h"
#include "auth_session.h"
@ -210,7 +210,7 @@ void SettingsWidget::onNotificationsChange() {
void SettingsWidget::onManageAdmins() {
if (auto chat = peer()->asChat()) {
Ui::show(Box<ContactsBox>(chat, MembersFilter::Admins));
EditChatAdminsBoxController::Start(chat);
} else if (auto channel = peer()->asChannel()) {
ParticipantsBoxController::Start(channel, ParticipantsBoxController::Role::Admins);
}

View File

@ -94,7 +94,7 @@ void ParticipantsBoxController::addNewItem() {
for (auto i = 0, count = delegate()->peerListFullRowsCount(); i != count; ++i) {
already.push_back(delegate()->peerListRowAt(i)->peer()->asUser());
}
ShowAddContactsToChannelBox(_channel, { already.begin(), already.end() });
AddParticipantsBoxController::Start(_channel, { already.begin(), already.end() });
}
return;
}

View File

@ -31,7 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "boxes/confirm_box.h"
#include "boxes/contacts_box.h"
#include "boxes/photo_crop_box.h"
#include "boxes/add_contact_box.h"
#include "boxes/peer_list_controllers.h"
#include "lang/lang_keys.h"
#include "apiwrap.h"
#include "auth_session.h"
@ -539,11 +539,11 @@ void CoverWidget::onAddMember() {
if (_peerChat->count >= Global::ChatSizeMax() && _peerChat->amCreator()) {
Ui::show(Box<ConvertToSupergroupBox>(_peerChat));
} else {
ShowAddContactsToChatBox(_peerChat);
AddParticipantsBoxController::Start(_peerChat);
}
} else if (_peerChannel && _peerChannel->mgInfo) {
auto &participants = _peerChannel->mgInfo->lastParticipants;
ShowAddContactsToChannelBox(_peerChannel, { participants.cbegin(), participants.cend() });
AddParticipantsBoxController::Start(_peerChannel, { participants.cbegin(), participants.cend() });
}
}

View File

@ -70,11 +70,12 @@ void WidgetSlideWrap<TWidget>::showAnimated() {
}
void WidgetSlideWrap<TWidget>::toggleFast(bool visible) {
if (visible) show();
_hiding = !visible;
if (!_hiding) show();
_a_height.finish();
_forceHeight = visible ? -1 : 0;
_forceHeight = _hiding ? 0 : -1;
resizeToWidth(_realSize.width());
if (!visible) hide();
if (_hiding) hide();
if (_updateCallback) {
_updateCallback();
}
@ -116,6 +117,7 @@ int WidgetSlideWrap<TWidget>::resizeGetHeight(int newWidth) {
if (resized) {
return _forceHeight;
}
_realSize = _entity->rectNoMargins().marginsAdded(_padding).size();
return _realSize.height();
}

View File

@ -62,6 +62,9 @@ public:
myEnsureResized(_entity);
animationCallback();
}
bool animating() const {
return _a_height.animating();
}
TWidget *entity() {
return _entity;