"Fossies" - the Fresh Open Source Software Archive

Member "tdesktop-2.6.1/Telegram/SourceFiles/info/feed/info_feed_channels_controllers.cpp" (24 Feb 2021, 13097 Bytes) of package /linux/misc/tdesktop-2.6.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "info_feed_channels_controllers.cpp" see the Fossies "Dox" file reference documentation.

    1 /*
    2 This file is part of Telegram Desktop,
    3 the official desktop application for the Telegram messaging service.
    4 
    5 For license and copyright information please follow this link:
    6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
    7 */
    8 #include "info/feed/info_feed_channels_controllers.h"
    9 
   10 #include "data/data_feed.h"
   11 #include "data/data_session.h"
   12 #include "data/data_channel.h"
   13 #include "info/info_controller.h"
   14 #include "lang/lang_keys.h"
   15 #include "history/history.h"
   16 #include "window/window_peer_menu.h"
   17 #include "ui/widgets/popup_menu.h"
   18 #include "ui/toast/toast.h"
   19 #include "auth_session.h"
   20 #include "mainwidget.h"
   21 #include "apiwrap.h"
   22 #include "styles/style_widgets.h"
   23 #include "styles/style_info.h"
   24 #include "styles/style_boxes.h"
   25 
   26 namespace Info {
   27 namespace FeedProfile {
   28 namespace {
   29 
   30 constexpr auto kChannelsInFeedMin = 4;
   31 
   32 } // namespace
   33 
   34 class ChannelsController::Row final : public PeerListRow {
   35 public:
   36     Row(not_null<History*> history);
   37 
   38     QSize actionSize() const override;
   39     QMargins actionMargins() const override;
   40     void paintAction(
   41         Painter &p,
   42         int x,
   43         int y,
   44         int outerWidth,
   45         bool selected,
   46         bool actionSelected) override;
   47 
   48     not_null<History*> history() const {
   49         return _history;
   50     }
   51 
   52 private:
   53     not_null<History*> _history;
   54 
   55 };
   56 
   57 ChannelsController::Row::Row(not_null<History*> history)
   58 : PeerListRow(history->peer)
   59 , _history(history) {
   60 }
   61 
   62 QSize ChannelsController::Row::actionSize() const {
   63     return QRect(
   64             QPoint(),
   65             st::smallCloseIcon.size()).marginsAdded(
   66                 st::infoFeedLeaveIconMargins).size();
   67 }
   68 
   69 QMargins ChannelsController::Row::actionMargins() const {
   70     return QMargins(
   71         0,
   72         (st::infoCommonGroupsList.item.height - actionSize().height()) / 2,
   73         0,
   74         0);
   75 }
   76 
   77 void ChannelsController::Row::paintAction(
   78         Painter &p,
   79         int x,
   80         int y,
   81         int outerWidth,
   82         bool selected,
   83         bool actionSelected) {
   84     if (selected) {
   85         x += st::infoFeedLeaveIconMargins.left();
   86         y += st::infoFeedLeaveIconMargins.top();
   87         (actionSelected
   88             ? st::smallCloseIconOver
   89             : st::smallCloseIcon).paint(p, x, y, outerWidth);
   90     }
   91 }
   92 
   93 ChannelsController::ChannelsController(not_null<Controller*> controller)
   94 : PeerListController()
   95 , _controller(controller)
   96 , _feed(_controller->key().feed()) {
   97     if (!_feed->channelsLoaded()) {
   98 //      Auth().api().requestFeedChannels(_feed); // #feed
   99     }
  100     _controller->setSearchEnabledByContent(false);
  101 }
  102 
  103 auto ChannelsController::createRow(not_null<History*> history)
  104 -> std::unique_ptr<Row> {
  105     auto result = std::make_unique<Row>(history);
  106     result->setCustomStatus(QString());
  107     return result;
  108 }
  109 
  110 std::unique_ptr<PeerListRow> ChannelsController::createRestoredRow(
  111         not_null<PeerData*> peer) {
  112     return createRow(peer->owner().history(peer));
  113 }
  114 
  115 void ChannelsController::prepare() {
  116     setSearchNoResultsText(lang(lng_feed_channels_not_found));
  117     delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled);
  118     delegate()->peerListSetTitle(langFactory(lng_info_feed_channels));
  119 
  120     rebuildRows();
  121     using Flag = Data::FeedUpdateFlag;
  122     Auth().data().feedUpdated(
  123     ) | rpl::filter([=](const Data::FeedUpdate &update) {
  124         return (update.feed == _feed) && (update.flag == Flag::Channels);
  125     }) | rpl::filter([=] {
  126         return _feed->channelsLoaded();
  127     }) | rpl::start_with_next([=] {
  128         rebuildRows();
  129     }, lifetime());
  130 }
  131 
  132 void ChannelsController::rebuildRows() {
  133     if (!_feed->channelsLoaded()) {
  134         return;
  135     }
  136     const auto &channels = _feed->channels();
  137     auto count = delegate()->peerListFullRowsCount();
  138     for (auto i = 0; i != count;) {
  139         const auto row = delegate()->peerListRowAt(i);
  140         const auto peer = row->peer();
  141         if (ranges::find_if(channels, [=](not_null<History*> history) {
  142             return (history->peer == peer);
  143         }) != end(channels)) {
  144             ++i;
  145         } else {
  146             delegate()->peerListRemoveRow(row);
  147             --count;
  148         }
  149     }
  150     for (const auto history : channels) {
  151         if (auto row = createRow(history)) {
  152             delegate()->peerListAppendRow(std::move(row));
  153         }
  154     }
  155     delegate()->peerListRefreshRows();
  156 }
  157 
  158 std::unique_ptr<PeerListState> ChannelsController::saveState() const {
  159     auto result = PeerListController::saveState();
  160     auto my = std::make_unique<SavedState>();
  161     using Flag = Data::FeedUpdateFlag;
  162 
  163     // Must not capture `this` here, because it dies before my->lifetime.
  164     Auth().data().feedUpdated(
  165     ) | rpl::filter([feed = _feed](const Data::FeedUpdate &update) {
  166         return (update.feed == feed) && (update.flag == Flag::Channels);
  167     }) | rpl::start_with_next([state = result.get()] {
  168         state->controllerState = nullptr;
  169     }, my->lifetime);
  170     result->controllerState = std::move(my);
  171     return result;
  172 }
  173 
  174 void ChannelsController::restoreState(
  175         std::unique_ptr<PeerListState> state) {
  176     PeerListController::restoreState(std::move(state));
  177 }
  178 
  179 void ChannelsController::rowClicked(not_null<PeerListRow*> row) {
  180     _controller->parentController()->showPeerHistory(
  181         row->peer(),
  182         Window::SectionShow::Way::Forward);
  183 }
  184 
  185 void ChannelsController::rowActionClicked(not_null<PeerListRow*> row) {
  186     Window::DeleteAndLeaveHandler(row->peer())();
  187 }
  188 
  189 base::unique_qptr<Ui::PopupMenu> ChannelsController::rowContextMenu(
  190         QWidget *parent,
  191         not_null<PeerListRow*> row) {
  192     auto my = static_cast<Row*>(row.get());
  193     auto channel = my->history()->peer->asChannel();
  194 
  195     auto result = base::make_unique_q<Ui::PopupMenu>(parent);
  196     Window::PeerMenuAddMuteAction(channel, [&](
  197             const QString &text,
  198             Fn<void()> handler) {
  199         return result->addAction(text, handler);
  200     });
  201     //result->addAction( // #feed
  202     //  lang(lng_feed_ungroup),
  203     //  [=] { Window::ToggleChannelGrouping(channel, false); });
  204 
  205     result->addAction(
  206         lang(lng_profile_leave_channel),
  207         Window::DeleteAndLeaveHandler(channel));
  208 
  209     return result;
  210 }
  211 
  212 void NotificationsController::Start(not_null<Data::Feed*> feed) {
  213     const auto initBox = [=](not_null<PeerListBox*> box) {
  214         box->addButton(langFactory(lng_settings_save), [=] {
  215             const auto count = box->peerListFullRowsCount();
  216             for (auto i = 0; i != count; ++i) {
  217                 const auto row = box->peerListRowAt(i);
  218                 const auto peer = row->peer();
  219                 const auto muted = !row->checked();
  220                 if (muted != Auth().data().notifyIsMuted(peer)) {
  221                     Auth().data().updateNotifySettings(
  222                         peer,
  223                         (muted
  224                             ? Data::NotifySettings::kDefaultMutePeriod
  225                             : 0));
  226                 }
  227             }
  228             box->closeBox();
  229         });
  230         box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); });
  231     };
  232     Ui::show(Box<PeerListBox>(
  233         std::make_unique<NotificationsController>(feed),
  234         initBox));
  235 }
  236 
  237 NotificationsController::NotificationsController(
  238     not_null<Data::Feed*> feed)
  239 : _feed(feed) {
  240 }
  241 
  242 void NotificationsController::prepare() {
  243     setSearchNoResultsText(lang(lng_feed_channels_not_found));
  244     delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled);
  245     delegate()->peerListSetTitle(langFactory(lng_feed_notifications));
  246 
  247     loadMoreRows();
  248 }
  249 
  250 void NotificationsController::loadMoreRows() {
  251     if (_preloadRequestId || _allLoaded) {
  252         return;
  253     }
  254     // const auto hash = 0;
  255     //_preloadRequestId = request(MTPmessages_GetDialogs( // #feed
  256     //  MTP_flags(MTPmessages_GetDialogs::Flag::f_feed_id),
  257     //  MTP_int(_feed->id()),
  258     //  MTP_int(_preloadOffsetDate),
  259     //  MTP_int(_preloadOffsetId),
  260     //  _preloadPeer ? _preloadPeer->input : MTP_inputPeerEmpty(),
  261     //  MTP_int(Data::Feed::kChannelsLimit),
  262     //  MTP_int(hash)
  263     //)).done([=](const MTPmessages_Dialogs &result) {
  264     //  applyFeedDialogs(result);
  265     //  _preloadRequestId = 0;
  266     //}).fail([=](const RPCError &error) {
  267     //  _preloadRequestId = 0;
  268     //}).send();
  269 }
  270 
  271 void NotificationsController::applyFeedDialogs(
  272         const MTPmessages_Dialogs &result) {
  273     const auto [dialogsList, messagesList] = [&] {
  274         const auto process = [&](const auto &data) {
  275             _feed->owner().processUsers(data.vusers);
  276             _feed->owner().processChats(data.vchats);
  277             return std::make_tuple(&data.vdialogs.v, &data.vmessages.v);
  278         };
  279         switch (result.type()) {
  280         case mtpc_messages_dialogs:
  281             _allLoaded = true;
  282             return process(result.c_messages_dialogs());
  283 
  284         case mtpc_messages_dialogsSlice:
  285             LOG(("API Error: "
  286                 "Unexpected dialogsSlice in feed dialogs list."));
  287             return process(result.c_messages_dialogsSlice());
  288         }
  289         Unexpected("Type in NotificationsController::applyFeedDialogs");
  290     }();
  291 
  292     App::feedMsgs(*messagesList, NewMessageLast);
  293 
  294     if (dialogsList->empty()) {
  295         _allLoaded = true;
  296     }
  297     auto channels = std::vector<not_null<ChannelData*>>();
  298     channels.reserve(dialogsList->size());
  299     for (const auto &dialog : *dialogsList) {
  300         dialog.match([&](const MTPDdialog &data) {
  301             if (const auto peerId = peerFromMTP(data.vpeer)) {
  302                 if (peerIsChannel(peerId)) { // #TODO archive
  303                     const auto history = Auth().data().history(peerId);
  304                     const auto channel = history->peer->asChannel();
  305                     history->applyDialog(data);
  306                     channels.emplace_back(channel);
  307                 } else {
  308                     LOG(("API Error: "
  309                         "Unexpected non-channel in folder dialogs list."));
  310                 }
  311             }
  312         }, [&](const MTPDdialogFolder &data) {
  313             LOG(("API Error: Unexpected dialogFolder in folder dialogs list."));
  314         });
  315     }
  316     if (!channels.empty()) {
  317         auto notMutedChannels = ranges::view::all(
  318             channels
  319         ) | ranges::view::filter([](not_null<ChannelData*> channel) {
  320             return !Auth().data().notifyIsMuted(channel);
  321         });
  322         delegate()->peerListAddSelectedRows(notMutedChannels);
  323         for (const auto channel : channels) {
  324             delegate()->peerListAppendRow(createRow(channel));
  325         }
  326     }
  327     delegate()->peerListRefreshRows();
  328 }
  329 
  330 void NotificationsController::rowClicked(not_null<PeerListRow*> row) {
  331     delegate()->peerListSetRowChecked(row, !row->checked());
  332 }
  333 
  334 std::unique_ptr<PeerListRow> NotificationsController::createRow(
  335         not_null<ChannelData*> channel) {
  336     return std::make_unique<PeerListRow>(channel);
  337 }
  338 
  339 void EditController::Start(
  340         not_null<Data::Feed*> feed,
  341         ChannelData *channel) {
  342     const auto initBox = [=](not_null<PeerListBox*> box) {
  343         box->addButton(langFactory(lng_settings_save), [=] {
  344             auto channels = std::vector<not_null<ChannelData*>>();
  345             const auto main = App::main();
  346             const auto count = box->peerListFullRowsCount();
  347             for (auto i = 0; i != count; ++i) {
  348                 const auto row = box->peerListRowAt(i);
  349                 if (row->checked()) {
  350                     channels.push_back(row->peer()->asChannel());
  351                 }
  352             }
  353             if (channels.size() < kChannelsInFeedMin) {
  354                 Ui::Toast::Show(lng_feed_select_more_channels(
  355                     lt_count,
  356                     kChannelsInFeedMin));
  357                 return;
  358             }
  359             box->closeBox();
  360             //Auth().api().setFeedChannels(feed, channels); // #feed
  361         });
  362         box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); });
  363     };
  364     Ui::show(Box<PeerListBox>(
  365         std::make_unique<EditController>(feed, channel),
  366         initBox));
  367 }
  368 
  369 EditController::EditController(
  370     not_null<Data::Feed*> feed,
  371     ChannelData *channel)
  372 : _feed(feed) {
  373 //, _startWithChannel(channel) { // #feed
  374 }
  375 
  376 void EditController::prepare() {
  377     setSearchNoResultsText(lang(lng_feed_channels_not_found));
  378     delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled);
  379     delegate()->peerListSetTitle(langFactory(
  380         (_feed->channels().size() < kChannelsInFeedMin
  381             ? lng_feed_create_new
  382             : lng_feed_edit_title)));
  383 
  384     loadMoreRows();
  385 }
  386 
  387 void EditController::loadMoreRows() {
  388     if (_preloadRequestId || _allLoaded) {
  389         return;
  390     }
  391     //const auto hash = 0; // #feed
  392     //_preloadRequestId = request(MTPchannels_GetFeedSources(
  393     //  MTP_flags(0),
  394     //  MTP_int(0),
  395     //  MTP_int(hash)
  396     //)).done([=](const MTPchannels_FeedSources &result) {
  397     //  applyFeedSources(result);
  398     //  _preloadRequestId = 0;
  399     //}).fail([=](const RPCError &error) {
  400     //  _preloadRequestId = 0;
  401     //}).send();
  402 }
  403 // #feed
  404 //void EditController::applyFeedSources(
  405 //      const MTPchannels_FeedSources &result) {
  406 //  auto channels = std::vector<not_null<ChannelData*>>();
  407 //
  408 //  switch (result.type()) {
  409 //  case mtpc_channels_feedSourcesNotModified:
  410 //      LOG(("API Error: Unexpected channels.feedSourcesNotModified."));
  411 //      break;
  412 //
  413 //  case mtpc_channels_feedSources: {
  414 //      const auto &data = result.c_channels_feedSources();
  415 //      Auth().api().applyFeedSources(data);
  416 //
  417 //      for (const auto &chat : data.vchats.v) {
  418 //          if (chat.type() == mtpc_channel) {
  419 //              channels.push_back(_feed->owner().channel(chat.c_channel().vid.v));
  420 //          }
  421 //      }
  422 //  } break;
  423 //
  424 //  default: Unexpected("Type in channels.getFeedSources response.");
  425 //  }
  426 //
  427 //  _allLoaded = true;
  428 //  if (channels.size() < kChannelsInFeedMin) {
  429 //      setDescriptionText(lng_feed_too_few_channels(
  430 //          lt_count,
  431 //          kChannelsInFeedMin));
  432 //      delegate()->peerListSetSearchMode(PeerListSearchMode::Disabled);
  433 //  } else {
  434 //      auto alreadyInFeed = ranges::view::all(
  435 //          channels
  436 //      ) | ranges::view::filter([&](not_null<ChannelData*> channel) {
  437 //          return (channel->feed() == _feed)
  438 //              || (channel == _startWithChannel);
  439 //      });
  440 //      delegate()->peerListAddSelectedRows(alreadyInFeed);
  441 //      for (const auto channel : channels) {
  442 //          delegate()->peerListAppendRow(createRow(channel));
  443 //      }
  444 //  }
  445 //  delegate()->peerListRefreshRows();
  446 //}
  447 
  448 void EditController::rowClicked(not_null<PeerListRow*> row) {
  449     delegate()->peerListSetRowChecked(row, !row->checked());
  450 }
  451 
  452 std::unique_ptr<PeerListRow> EditController::createRow(
  453         not_null<ChannelData*> channel) {
  454     return std::make_unique<PeerListRow>(channel);
  455 }
  456 
  457 } // namespace FeedProfile
  458 } // namespace Info