/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "boxes/peers/edit_linked_chat_box.h" #include "lang/lang_keys.h" #include "data/data_channel.h" #include "data/data_chat.h" #include "data/data_changes.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "ui/wrap/vertical_layout.h" #include "ui/text/text_utilities.h" // Ui::Text::ToUpper #include "boxes/peer_list_box.h" #include "ui/boxes/confirm_box.h" #include "boxes/add_contact_box.h" #include "apiwrap.h" #include "main/main_session.h" #include "window/window_session_controller.h" #include "styles/style_layers.h" #include "styles/style_boxes.h" #include "styles/style_info.h" namespace { constexpr auto kEnableSearchRowsCount = 10; class Controller : public PeerListController, public base::has_weak_ptr { public: Controller( not_null channel, ChannelData *chat, const std::vector> &chats, Fn callback, Fn)> showHistoryCallback); Main::Session &session() const override; void prepare() override; void rowClicked(not_null row) override; int contentWidth() const override; private: void choose(not_null chat); void choose(not_null chat); not_null _channel; ChannelData *_chat = nullptr; std::vector> _chats; Fn _callback; Fn)> _showHistoryCallback; ChannelData *_waitForFull = nullptr; rpl::event_stream> _showHistoryRequest; }; Controller::Controller( not_null channel, ChannelData *chat, const std::vector> &chats, Fn callback, Fn)> showHistoryCallback) : _channel(channel) , _chat(chat) , _chats(std::move(chats)) , _callback(std::move(callback)) , _showHistoryCallback(std::move(showHistoryCallback)) { channel->session().changes().peerUpdates( Data::PeerUpdate::Flag::FullInfo ) | rpl::filter([=](const Data::PeerUpdate &update) { return (update.peer == _waitForFull); }) | rpl::start_with_next([=](const Data::PeerUpdate &update) { choose(std::exchange(_waitForFull, nullptr)); }, lifetime()); } Main::Session &Controller::session() const { return _channel->session(); } int Controller::contentWidth() const { return st::boxWidth; } void Controller::prepare() { const auto appendRow = [&](not_null chat) { if (delegate()->peerListFindRow(chat->id.value)) { return; } auto row = std::make_unique(chat); const auto username = chat->userName(); row->setCustomStatus(!username.isEmpty() ? ('@' + username) : (chat->isChannel() && !chat->isMegagroup()) ? tr::lng_manage_linked_channel_private_status(tr::now) : tr::lng_manage_discussion_group_private_status(tr::now)); delegate()->peerListAppendRow(std::move(row)); }; if (_chat) { appendRow(_chat); } else { for (const auto chat : _chats) { appendRow(chat); } if (_chats.size() >= kEnableSearchRowsCount) { delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); } } } void Controller::rowClicked(not_null row) { if (_chat != nullptr) { _showHistoryCallback(_chat); return; } const auto peer = row->peer(); if (const auto channel = peer->asChannel()) { if (channel->wasFullUpdated()) { choose(channel); return; } _waitForFull = channel; channel->updateFull(); } else if (const auto chat = peer->asChat()) { choose(chat); } } void Controller::choose(not_null chat) { auto text = tr::lng_manage_discussion_group_sure( tr::now, lt_group, Ui::Text::Bold(chat->name), lt_channel, Ui::Text::Bold(_channel->name), Ui::Text::WithEntities); if (!_channel->isPublic()) { text.append( "\n\n" + tr::lng_manage_linked_channel_private(tr::now)); } if (!chat->isPublic()) { text.append( "\n\n" + tr::lng_manage_discussion_group_private(tr::now)); if (chat->hiddenPreHistory()) { text.append("\n\n"); text.append(tr::lng_manage_discussion_group_warning( tr::now, Ui::Text::RichLangValue)); } } const auto sure = [=](Fn &&close) { close(); const auto onstack = _callback; onstack(chat); }; delegate()->peerListShowBox( Ui::MakeConfirmBox({ .text = text, .confirmed = sure, .confirmText = tr::lng_manage_discussion_group_link(tr::now), }), Ui::LayerOption::KeepOther); } void Controller::choose(not_null chat) { auto text = tr::lng_manage_discussion_group_sure( tr::now, lt_group, Ui::Text::Bold(chat->name), lt_channel, Ui::Text::Bold(_channel->name), Ui::Text::WithEntities); if (!_channel->isPublic()) { text.append("\n\n" + tr::lng_manage_linked_channel_private(tr::now)); } text.append("\n\n" + tr::lng_manage_discussion_group_private(tr::now)); text.append("\n\n"); text.append(tr::lng_manage_discussion_group_warning( tr::now, Ui::Text::RichLangValue)); const auto sure = [=](Fn &&close) { close(); const auto done = [=](not_null chat) { const auto onstack = _callback; onstack(chat); }; chat->session().api().migrateChat(chat, crl::guard(this, done)); }; delegate()->peerListShowBox( Ui::MakeConfirmBox({ .text = text, .confirmed = sure, .confirmText = tr::lng_manage_discussion_group_link(tr::now), }), Ui::LayerOption::KeepOther); } object_ptr SetupAbout( not_null parent, not_null channel, ChannelData *chat) { auto about = object_ptr( parent, QString(), st::linkedChatAbout); about->setMarkedText([&] { if (!channel->isBroadcast()) { return tr::lng_manage_linked_channel_about( tr::now, lt_channel, Ui::Text::Bold(chat->name), Ui::Text::WithEntities); } else if (chat != nullptr) { return tr::lng_manage_discussion_group_about_chosen( tr::now, lt_group, Ui::Text::Bold(chat->name), Ui::Text::WithEntities); } return tr::lng_manage_discussion_group_about( tr::now, Ui::Text::WithEntities); }()); return about; } object_ptr SetupFooter( not_null parent, not_null channel) { return object_ptr( parent, (channel->isBroadcast() ? tr::lng_manage_discussion_group_posted : tr::lng_manage_linked_channel_posted)(), st::linkedChatAbout); } object_ptr SetupCreateGroup( not_null parent, not_null navigation, not_null channel, Fn callback) { Expects(channel->isBroadcast()); auto result = object_ptr( parent, tr::lng_manage_discussion_group_create( ) | Ui::Text::ToUpper(), st::infoCreateLinkedChatButton); result->addClickHandler([=] { const auto guarded = crl::guard(parent, callback); Window::Show(navigation).showBox( Box( navigation, GroupInfoBox::Type::Megagroup, channel->name + " Chat", guarded), Ui::LayerOption::KeepOther); }); return result; } object_ptr SetupUnlink( not_null parent, not_null channel, Fn callback) { auto result = object_ptr( parent, (channel->isBroadcast() ? tr::lng_manage_discussion_group_unlink : tr::lng_manage_linked_channel_unlink)() | Ui::Text::ToUpper(), st::infoUnlinkChatButton); result->addClickHandler([=] { callback(nullptr); }); return result; } object_ptr EditLinkedChatBox( not_null navigation, not_null channel, ChannelData *chat, std::vector> &&chats, bool canEdit, Fn callback) { Expects((channel->isBroadcast() && canEdit) || (chat != nullptr)); 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, navigation, channel, callback)); } box->peerListSetAboveWidget(std::move(above)); auto below = object_ptr(box); if (chat && canEdit) { below->add(SetupUnlink(below, channel, callback)); } below->add( SetupFooter(below, channel), st::linkedChatAboutPadding); box->peerListSetBelowWidget(std::move(below)); box->setTitle(channel->isBroadcast() ? tr::lng_manage_discussion_group() : tr::lng_manage_linked_channel()); box->addButton(tr::lng_close(), [=] { box->closeBox(); }); }; auto showHistoryCallback = [=](not_null peer) { navigation->showPeerHistory( peer, Window::SectionShow::Way::ClearStack, ShowAtUnreadMsgId); }; auto controller = std::make_unique( channel, chat, std::move(chats), std::move(callback), std::move(showHistoryCallback)); return Box(std::move(controller), init); } } // namespace object_ptr EditLinkedChatBox( not_null navigation, not_null channel, std::vector> &&chats, Fn callback) { return EditLinkedChatBox( navigation, channel, nullptr, std::move(chats), true, callback); } object_ptr EditLinkedChatBox( not_null navigation, not_null channel, not_null chat, bool canEdit, Fn callback) { return EditLinkedChatBox( navigation, channel, chat, {}, canEdit, callback); }