diff --git a/Telegram/SourceFiles/boxes/add_contact_box.cpp b/Telegram/SourceFiles/boxes/add_contact_box.cpp index db8e888b5a..0cffd3c847 100644 --- a/Telegram/SourceFiles/boxes/add_contact_box.cpp +++ b/Telegram/SourceFiles/boxes/add_contact_box.cpp @@ -134,6 +134,8 @@ void ShowAddParticipantsError( return lang(lng_failed_add_not_mutual); } else if (error == qstr("USER_ALREADY_PARTICIPANT") && hasBot) { return lang(lng_bot_already_in_group); + } else if (error == qstr("BOT_GROUPS_BLOCKED")) { + return lang(lng_error_cant_add_bot); } else if (error == qstr("PEER_FLOOD")) { const auto isGroup = (chat->isChat() || chat->isMegagroup()); return PeerFloodErrorText(isGroup diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index 4e7cb0d4fc..97943fd025 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -73,7 +73,7 @@ void PeerListBox::createMultiSelect() { _controller->itemDeselectedHook(peer); } }); - _select->resizeToWidth(st::boxWideWidth); + _select->resizeToWidth(_controller->contentWidth()); _select->moveToLeft(0, 0); } @@ -101,11 +101,11 @@ void PeerListBox::prepare() { _controller.get(), st::peerListBox), st::boxLayerScroll)); - content()->resizeToWidth(st::boxWideWidth); + content()->resizeToWidth(_controller->contentWidth()); _controller->setDelegate(this); - setDimensions(st::boxWideWidth, st::boxMaxListHeight); + setDimensions(_controller->contentWidth(), st::boxMaxListHeight); if (_select) { _select->finishAnimating(); Ui::SendPendingMoveResizeEvents(_select); @@ -281,6 +281,10 @@ void PeerListController::restoreState( delegate()->peerListRestoreState(std::move(state)); } +int PeerListController::contentWidth() const { + return st::boxWideWidth; +} + void PeerListBox::addSelectItem(not_null peer, PeerListRow::SetStyle style) { if (!_select) { createMultiSelect(); @@ -825,13 +829,20 @@ void PeerListContent::setSearchNoResults(object_ptr noResults) { } } -void PeerListContent::setAboveWidget(object_ptr aboveWidget) { - _aboveWidget = std::move(aboveWidget); +void PeerListContent::setAboveWidget(object_ptr widget) { + _aboveWidget = std::move(widget); if (_aboveWidget) { _aboveWidget->setParent(this); } } +void PeerListContent::setBelowWidget(object_ptr widget) { + _belowWidget = std::move(widget); + if (_belowWidget) { + _belowWidget->setParent(this); + } +} + int PeerListContent::labelHeight() const { auto computeLabelHeight = [](auto &label) { if (!label) { @@ -937,9 +948,9 @@ int PeerListContent::resizeGetHeight(int newWidth) { _aboveHeight = _aboveWidget->height(); } } - auto rowsCount = shownRowsCount(); - auto labelTop = rowsTop() + qMax(1, shownRowsCount()) * _rowHeight; - auto labelWidth = newWidth - 2 * st::contactsPadding.left(); + const auto rowsCount = shownRowsCount(); + const auto labelTop = rowsTop() + qMax(1, shownRowsCount()) * _rowHeight; + const auto labelWidth = newWidth - 2 * st::contactsPadding.left(); if (_description) { _description->resizeToWidth(labelWidth); _description->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top(), newWidth); @@ -955,9 +966,22 @@ int PeerListContent::resizeGetHeight(int newWidth) { _searchLoading->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top(), newWidth); _searchLoading->setVisible(showingSearch() && _filterResults.empty() && _controller->isSearchLoading()); } - auto label = labelHeight(); - return ((label > 0 || rowsCount > 0) ? (labelTop + label) : 0) - + _st.padding.bottom(); + const auto label = labelHeight(); + const auto belowTop = (label > 0 || rowsCount > 0) + ? (labelTop + label + _st.padding.bottom()) + : _aboveHeight; + _belowHeight = 0; + if (_belowWidget) { + _belowWidget->resizeToWidth(newWidth); + _belowWidget->moveToLeft(0, belowTop, newWidth); + if (showingSearch()) { + _belowWidget->hide(); + } else { + _belowWidget->show(); + _belowHeight = _belowWidget->height(); + } + } + return belowTop + _belowHeight; } void PeerListContent::enterEventHook(QEvent *e) { diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h index 67ef59e698..ae12484ea6 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.h +++ b/Telegram/SourceFiles/boxes/peer_list_box.h @@ -231,6 +231,7 @@ public: virtual void peerListSetSearchLoading(object_ptr loading) = 0; virtual void peerListSetSearchNoResults(object_ptr noResults) = 0; virtual void peerListSetAboveWidget(object_ptr aboveWidget) = 0; + virtual void peerListSetBelowWidget(object_ptr belowWidget) = 0; virtual void peerListSetSearchMode(PeerListSearchMode mode) = 0; virtual void peerListAppendRow(std::unique_ptr row) = 0; virtual void peerListAppendSearchRow(std::unique_ptr row) = 0; @@ -358,6 +359,8 @@ public: virtual void restoreState( std::unique_ptr state); + virtual int contentWidth() const; + bool isRowSelected(not_null peer) { return delegate()->peerListIsRowSelected(peer); } @@ -457,7 +460,8 @@ public: void setDescription(object_ptr description); void setSearchLoading(object_ptr loading); void setSearchNoResults(object_ptr noResults); - void setAboveWidget(object_ptr aboveWidget); + void setAboveWidget(object_ptr widget); + void setBelowWidget(object_ptr width); void refreshRows(); void setSearchMode(PeerListSearchMode mode); @@ -613,7 +617,9 @@ private: std::vector> _filterResults; int _aboveHeight = 0; + int _belowHeight = 0; object_ptr _aboveWidget = { nullptr }; + object_ptr _belowWidget = { nullptr }; object_ptr _description = { nullptr }; object_ptr _searchNoResults = { nullptr }; object_ptr _searchLoading = { nullptr }; @@ -692,6 +698,9 @@ public: void peerListSetAboveWidget(object_ptr aboveWidget) override { _content->setAboveWidget(std::move(aboveWidget)); } + void peerListSetBelowWidget(object_ptr belowWidget) override { + _content->setBelowWidget(std::move(belowWidget)); + } void peerListSetSearchMode(PeerListSearchMode mode) override { _content->setSearchMode(mode); } diff --git a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp index b642e079ac..56fd967c3e 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.cpp @@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { +constexpr auto kEnableSearchRowsCount = 10; + TextWithEntities BoldText(const QString &text) { auto result = TextWithEntities{ text }; result.entities.push_back( @@ -28,109 +30,95 @@ TextWithEntities BoldText(const QString &text) { return result; } -class ListController - : public PeerListController - , public PeerListContentDelegate { +class Controller : public PeerListController { public: - ListController(Fn)> callback) - : _callback(std::move(callback)) { - } - void prepare() override { - } - void rowClicked(not_null row) override { - const auto onstack = _callback; - onstack(row->peer()->asChannel()); - } - void peerListSetTitle(Fn title) override { - } - void peerListSetAdditionalTitle(Fn title) override { - } - bool peerListIsRowSelected(not_null peer) override { - return false; - } - int peerListSelectedRowsCount() override { - return 0; - } - auto peerListCollectSelectedRows() - -> std::vector> override { - return {}; - } - void peerListScrollToTop() override { - } - void peerListAddSelectedRowInBunch( - not_null peer) override { - } - void peerListFinishSelectedRowsBunch() override { - } - void peerListSetDescription( - object_ptr description) override { - } - -private: - Fn)> _callback; - -}; - -object_ptr SetupList( - not_null parent, + Controller( not_null channel, ChannelData *chat, const std::vector> &chats, - Fn callback) { - const auto already = (chat != nullptr); - const auto selected = [=](not_null chat) { - if (already) { - Ui::showPeerHistory(chat, ShowAtUnreadMsgId); - } else { - auto text = lng_manage_discussion_group_sure__generic< - TextWithEntities - >( - lt_group, - BoldText(chat->name), - lt_channel, - BoldText(channel->name)); - if (!channel->isPublic()) { - text.append( - "\n\n" + lang(lng_manage_linked_channel_private)); - } - const auto box = std::make_shared>(); - const auto sure = [=] { - if (*box) { - (*box)->closeBox(); - } - callback(chat); - }; - *box = Ui::show( - Box( - text, - lang(lng_manage_discussion_group_link), - sure), - LayerOption::KeepOther); + Fn callback); + + void prepare() override; + void rowClicked(not_null row) override; + int contentWidth() const override; + +private: + not_null _channel; + ChannelData *_chat = nullptr; + std::vector> _chats; + Fn _callback; + +}; + +Controller::Controller( + not_null channel, + ChannelData *chat, + const std::vector> &chats, + Fn callback) +: _channel(channel) +, _chat(chat) +, _chats(std::move(chats)) +, _callback(std::move(callback)) { +} + +int Controller::contentWidth() const { + return st::boxWidth; +} + +void Controller::prepare() { + const auto appendRow = [&](not_null chat) { + if (delegate()->peerListFindRow(chat->id)) { + return; } - }; - const auto controller = Ui::CreateChild( - parent.get(), - selected); - controller->setDelegate(controller); - auto list = object_ptr( - parent, - controller, - st::peerListBox); - const auto createRow = [](not_null chat) { - auto result = std::make_unique(chat); - result->setCustomStatus(chat->isPublic() + auto row = std::make_unique(chat); + row->setCustomStatus(chat->isPublic() ? ('@' + chat->username) : lang(lng_manage_discussion_group_private)); - return result; + delegate()->peerListAppendRow(std::move(row)); }; - if (chat) { - list->appendRow(createRow(chat)); + if (_chat) { + appendRow(_chat); } else { - for (const auto chat : chats) { - list->appendRow(createRow(chat)); + for (const auto chat : _chats) { + appendRow(chat); + } + if (_chats.size() >= kEnableSearchRowsCount) { + delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); } } - return std::move(list); +} + +void Controller::rowClicked(not_null row) { + if (_chat != nullptr) { + Ui::showPeerHistory(_chat, ShowAtUnreadMsgId); + return; + } + const auto chat = row->peer()->asChannel(); + auto text = lng_manage_discussion_group_sure__generic< + TextWithEntities + >( + lt_group, + BoldText(chat->name), + lt_channel, + BoldText(_channel->name)); + if (!_channel->isPublic()) { + text.append( + "\n\n" + lang(lng_manage_linked_channel_private)); + } + const auto box = std::make_shared>(); + const auto sure = [=] { + if (*box) { + (*box)->closeBox(); + } + const auto onstack = _callback; + onstack(chat); + }; + *box = Ui::show( + Box( + text, + lang(lng_manage_discussion_group_link), + sure), + LayerOption::KeepOther); } object_ptr SetupAbout( @@ -211,58 +199,57 @@ object_ptr SetupUnlink( return result; } -} // namespace - -EditLinkedChatBox::EditLinkedChatBox( - QWidget*, - not_null channel, - const std::vector> &chats, - Fn callback) -: _channel(channel) -, _content(setupContent(channel, nullptr, chats, callback)) { -} - -EditLinkedChatBox::EditLinkedChatBox( - QWidget*, - not_null channel, - not_null chat, - Fn callback) -: _channel(channel) -, _content(setupContent(channel, chat, {}, callback)) { -} - -object_ptr EditLinkedChatBox::setupContent( +object_ptr EditLinkedChatBox( not_null channel, ChannelData *chat, - const std::vector> &chats, + std::vector> &&chats, Fn callback) { Expects(channel->isBroadcast() || (chat != nullptr)); - auto result = object_ptr(this); - result->add( - SetupAbout(result, channel, chat), - st::linkedChatAboutPadding); - if (!chat) { - result->add(SetupCreateGroup(result, channel, callback)); - } - result->add(SetupList(result, channel, chat, chats, callback)); - if (chat) { - result->add(SetupUnlink(result, channel, callback)); - } - result->add( - SetupFooter(result, channel), - st::linkedChatAboutPadding); - return result; + const auto init = [=](not_null box) { + auto above = object_ptr(box); + above->add( + SetupAbout(above, channel, chat), + st::linkedChatAboutPadding); + if (!chat) { + above->add(SetupCreateGroup(above, channel, callback)); + } + box->peerListSetAboveWidget(std::move(above)); + + auto below = object_ptr(box); + if (chat) { + below->add(SetupUnlink(below, channel, callback)); + } + below->add( + SetupFooter(below, channel), + st::linkedChatAboutPadding); + box->peerListSetBelowWidget(std::move(below)); + + box->setTitle(langFactory(channel->isBroadcast() + ? lng_manage_discussion_group + : lng_manage_linked_channel)); + box->addButton(langFactory(lng_close), [=] { box->closeBox(); }); + }; + auto controller = std::make_unique( + channel, + chat, + std::move(chats), + std::move(callback)); + return Box(std::move(controller), init); } -void EditLinkedChatBox::prepare() { - setTitle(langFactory(_channel->isBroadcast() - ? lng_manage_discussion_group - : lng_manage_linked_channel)); +} // namespace - setDimensionsToContent( - st::boxWidth, - setInnerWidget(std::move(_content))); - - addButton(langFactory(lng_close), [=] { closeBox(); }); +object_ptr EditLinkedChatBox( + not_null channel, + std::vector> &&chats, + Fn callback) { + return EditLinkedChatBox(channel, nullptr, std::move(chats), callback); +} + +object_ptr EditLinkedChatBox( + not_null channel, + not_null chat, + Fn callback) { + return EditLinkedChatBox(channel, chat, {}, callback); } diff --git a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.h b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.h index f1f0b6a1af..77e36a6d77 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_linked_chat_box.h @@ -9,30 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/abstract_box.h" -class EditLinkedChatBox : public BoxContent { -public: - EditLinkedChatBox( - QWidget*, - not_null channel, - not_null chat, - Fn callback); - EditLinkedChatBox( - QWidget*, - not_null channel, - const std::vector> &chats, - Fn callback); +object_ptr EditLinkedChatBox( + not_null channel, + not_null chat, + Fn callback); -protected: - void prepare() override; - -private: - object_ptr setupContent( - not_null channel, - ChannelData *chat, - const std::vector> &chats, - Fn callback); - - not_null _channel; - object_ptr _content; - -}; \ No newline at end of file +object_ptr EditLinkedChatBox( + not_null channel, + std::vector> &&chats, + Fn callback); diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index 465f4a32b4..0932a12a5d 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -518,7 +518,7 @@ void Controller::showEditLinkedChatBox() { }; if (const auto chat = *_linkedChatSavedValue) { *box = Ui::show( - Box(channel, chat, callback), + EditLinkedChatBox(channel, chat, callback), LayerOption::KeepOther); return; } else if (_linkedChatsRequestId) { @@ -541,10 +541,11 @@ void Controller::showEditLinkedChatBox() { const auto chat = _peer->owner().processChat(item); if (chat->isChannel()) { chats.emplace_back(chat->asChannel()); + } else if (chat->isChat()) { } } *box = Ui::show( - Box(channel, chats, callback), + EditLinkedChatBox(channel, std::move(chats), callback), LayerOption::KeepOther); }).fail([=](const RPCError &error) { _linkedChatsRequestId = 0; @@ -779,7 +780,7 @@ void Controller::fillManageSection() { return !isChannel ? false : channel->isBroadcast() - ? (channel->linkedChat() && channel->canEditInformation()) + ? channel->canEditInformation() : (channel->linkedChat() && channel->canPinMessages() && channel->adminRights() != 0); diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style index f54d1569a1..0b7ef4ea37 100644 --- a/Telegram/SourceFiles/info/info.style +++ b/Telegram/SourceFiles/info/info.style @@ -436,7 +436,7 @@ infoBlockButton: InfoProfileButton(infoProfileButton) { textFgOver: attentionButtonFgOver; } infoCreateLinkedChatButton: InfoProfileButton(infoMainButton) { - padding: margins(73px, 10px, 8px, 8px); + padding: margins(74px, 10px, 8px, 8px); } infoUnlinkChatButton: InfoProfileButton(infoCreateLinkedChatButton) { textFg: attentionButtonFg;