diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 694141ca7..534bcd97b 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -2637,12 +2637,81 @@ void ApiWrap::userPhotosDone( )); } +void ApiWrap::requestFeedChannels(not_null feed) { + if (_feedChannelsRequests.contains(feed)) { + return; + } + const auto hash = feed->channelsHash(); + request(MTPchannels_GetFeedSources( + MTP_flags(MTPchannels_GetFeedSources::Flag::f_feed_id), + MTP_int(feed->id()), + MTP_int(hash) + )).done([=](const MTPchannels_FeedSources &result) { + _feedChannelsRequests.remove(feed); + + switch (result.type()) { + case mtpc_channels_feedSourcesNotModified: + if (feed->channelsHash() == hash) { + feedChannelsDone(feed); + } else { + requestFeedChannels(feed); + } + break; + + case mtpc_channels_feedSources: { + const auto &data = result.c_channels_feedSources(); + App::feedUsers(data.vusers); + App::feedChats(data.vchats); + for (const auto &broadcasts : data.vfeeds.v) { + if (broadcasts.type() == mtpc_feedBroadcasts) { + const auto &list = broadcasts.c_feedBroadcasts(); + const auto feedId = list.vfeed_id.v; + const auto feed = _session->data().feed(feedId); + auto channels = std::vector>(); + for (const auto &channelId : list.vchannels.v) { + channels.push_back(App::channel(channelId.v)); + } + feed->setChannels(std::move(channels)); + } + } + if (feed->channelsLoaded()) { + feedChannelsDone(feed); + } else { + LOG(("API Error: feed channels not received for " + ).arg(feed->id())); + } + } break; + + default: Unexpected("Type in channels.getFeedSources response."); + } + }).fail([=](const RPCError &error) { + _feedChannelsRequests.remove(feed); + }).send(); + _feedChannelsRequests.emplace(feed); +} + +void ApiWrap::feedChannelsDone(not_null feed) { + feed->setChannelsLoaded(true); + for (const auto key : base::take(_feedMessagesRequestsPending)) { + std::apply( + [=](auto&&...args) { requestFeedMessages(args...); }, + key); + } +} + void ApiWrap::requestFeedMessages( not_null feed, Data::MessagePosition messageId, SliceType slice) { const auto key = std::make_tuple(feed, messageId, slice); - if (_feedMessagesRequests.contains(key)) { + if (_feedMessagesRequests.contains(key) + || _feedMessagesRequestsPending.contains(key)) { + return; + } + + if (!feed->channelsLoaded()) { + _feedMessagesRequestsPending.emplace(key); + requestFeedChannels(feed); return; } @@ -2656,7 +2725,7 @@ void ApiWrap::requestFeedMessages( } Unexpected("Direction in PrepareSearchRequest"); }(); - const auto sourcesHash = int32(0);// feed->channelsHash(); // #TODO + const auto sourcesHash = feed->channelsHash(); const auto hash = int32(0); const auto flags = (messageId && messageId.fullId.channel) ? MTPchannels_GetFeed::Flag::f_offset_position @@ -2681,7 +2750,7 @@ void ApiWrap::requestFeedMessages( }).fail([=](const RPCError &error) { _feedMessagesRequests.remove(key); }).send(); - _feedMessagesRequests.emplace(key, requestId); + _feedMessagesRequests.emplace(key); } void ApiWrap::feedMessagesDone( diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 457f4414c..5e3c46298 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -161,6 +161,8 @@ public: not_null user, PhotoId afterId); + void requestFeedChannels( + not_null feed); void requestFeedMessages( not_null feed, Data::MessagePosition messageId, @@ -323,6 +325,7 @@ private: PhotoId photoId, const MTPphotos_Photos &result); + void feedChannelsDone(not_null feed); void feedMessagesDone( not_null feed, Data::MessagePosition messageId, @@ -450,10 +453,15 @@ private: base::flat_map, mtpRequestId> _userPhotosRequests; - base::flat_map> _feedChannelsRequests; + base::flat_set, Data::MessagePosition, - SliceType>, mtpRequestId> _feedMessagesRequests; + SliceType>> _feedMessagesRequests; + base::flat_set, + Data::MessagePosition, + SliceType>> _feedMessagesRequestsPending; rpl::event_stream _sendActions; diff --git a/Telegram/SourceFiles/data/data_feed.cpp b/Telegram/SourceFiles/data/data_feed.cpp index eeb98af69..eb0742c47 100644 --- a/Telegram/SourceFiles/data/data_feed.cpp +++ b/Telegram/SourceFiles/data/data_feed.cpp @@ -162,6 +162,49 @@ int32 Feed::channelsHash() const { })); } +bool Feed::channelsLoaded() const { + return _channelsLoaded; +} + +void Feed::setChannelsLoaded(bool loaded) { + _channelsLoaded = loaded; +} + +void Feed::setChannels(std::vector> channels) { + const auto remove = ranges::view::all( + _channels + ) | ranges::view::transform([](not_null history) { + return history->peer->asChannel(); + }) | ranges::view::filter([&](not_null channel) { + return !base::contains(channels, channel); + }) | ranges::to_vector; + + const auto add = ranges::view::all( + channels + ) | ranges::view::filter([&](not_null channel) { + return ranges::find( + _channels, + channel.get(), + [](auto history) { return history->peer->asChannel(); } + ) != end(_channels); + }) | ranges::to_vector; + + for (const auto channel : remove) { + channel->clearFeed(); + } + for (const auto channel : add) { + channel->setFeed(this); + } + + _channels.clear(); + for (const auto channel : channels) { + Assert(channel->feed() == this); + + _channels.push_back(App::history(channel)); + } + _channelsLoaded = true; +} + bool Feed::justSetLastMessage(not_null item) { if (_lastMessage && item->position() <= _lastMessage->position()) { return false; diff --git a/Telegram/SourceFiles/data/data_feed.h b/Telegram/SourceFiles/data/data_feed.h index bba7b9109..2ff450778 100644 --- a/Telegram/SourceFiles/data/data_feed.h +++ b/Telegram/SourceFiles/data/data_feed.h @@ -66,6 +66,9 @@ public: const std::vector> &channels() const; int32 channelsHash() const; + bool channelsLoaded() const; + void setChannelsLoaded(bool loaded); + void setChannels(std::vector> channels); private: void indexNameParts(); @@ -75,6 +78,7 @@ private: FeedId _id = 0; not_null _parent; std::vector> _channels; + bool _channelsLoaded = false; QString _name; base::flat_set _nameWords; diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 503e0fc40..6055a7931 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -185,23 +185,39 @@ void paintRow( icon.paint(p, fullWidth - st::dialogsPadding.x() - icon.width(), texttop, fullWidth); availableWidth -= icon.width() + st::dialogsUnreadPadding; } - auto sendStateIcon = ([draft, item, active, selected]() -> const style::icon* { + auto sendStateIcon = [&]() -> const style::icon* { if (draft) { if (draft->saveRequestId) { - return &(active ? st::dialogsSendingIconActive : (selected ? st::dialogsSendingIconOver : st::dialogsSendingIcon)); + return &(active + ? st::dialogsSendingIconActive + : (selected + ? st::dialogsSendingIconOver + : st::dialogsSendingIcon)); } } else if (item && !item->isEmpty() && item->needCheck()) { if (item->id > 0) { if (item->unread()) { - return &(active ? st::dialogsSentIconActive : (selected ? st::dialogsSentIconOver : st::dialogsSentIcon)); + return &(active + ? st::dialogsSentIconActive + : (selected + ? st::dialogsSentIconOver + : st::dialogsSentIcon)); } - return &(active ? st::dialogsReceivedIconActive : (selected ? st::dialogsReceivedIconOver : st::dialogsReceivedIcon)); + return &(active + ? st::dialogsReceivedIconActive + : (selected + ? st::dialogsReceivedIconOver + : st::dialogsReceivedIcon)); } - return &(active ? st::dialogsSendingIconActive : (selected ? st::dialogsSendingIconOver : st::dialogsSendingIcon)); + return &(active + ? st::dialogsSendingIconActive + : (selected + ? st::dialogsSendingIconOver + : st::dialogsSendingIcon)); } return nullptr; - })(); - if (sendStateIcon) { + }(); + if (sendStateIcon && history) { rectForName.setWidth(rectForName.width() - st::dialogsSendStateSkip); sendStateIcon->paint(p, rectForName.topLeft() + QPoint(rectForName.width(), 0), fullWidth); } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 847f116c1..b057e098a 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -236,6 +236,7 @@ ListWidget::ListWidget( , _delegate(delegate) , _controller(controller) , _context(_delegate->listContext()) +, _itemAverageHeight(itemMinimalHeight()) , _scrollDateCheck([this] { scrollDateCheck(); }) , _selectEnabled(_delegate->listAllowsMultiSelect()) { setMouseTracking(true); @@ -782,6 +783,12 @@ void ListWidget::setTextSelection( } } +int ListWidget::itemMinimalHeight() const { + return st::msgMarginTopAttached + + st::msgPhotoSize + + st::msgMargin.bottom(); +} + void ListWidget::checkMoveToOtherViewer() { auto visibleHeight = (_visibleBottom - _visibleTop); if (width() <= 0 @@ -795,13 +802,10 @@ void ListWidget::checkMoveToOtherViewer() { auto topItem = findItemByY(_visibleTop); auto bottomItem = findItemByY(_visibleBottom); auto preloadedHeight = kPreloadedScreensCountFull * visibleHeight; - auto minItemHeight = st::msgMarginTopAttached - + st::msgPhotoSize - + st::msgMargin.bottom(); - auto preloadedCount = preloadedHeight / minItemHeight; + auto preloadedCount = preloadedHeight / _itemAverageHeight; auto preloadIdsLimitMin = (preloadedCount / 2) + 1; auto preloadIdsLimit = preloadIdsLimitMin - + (visibleHeight / minItemHeight); + + (visibleHeight / _itemAverageHeight); auto preloadBefore = kPreloadIfLessThanScreens * visibleHeight; auto before = _slice.skippedBefore; @@ -814,7 +818,7 @@ void ListWidget::checkMoveToOtherViewer() { auto minScreenDelta = kPreloadedScreensCount - kPreloadIfLessThanScreens; auto minUniversalIdDelta = (minScreenDelta * visibleHeight) - / minItemHeight; + / _itemAverageHeight; auto preloadAroundMessage = [&](not_null view) { auto preloadRequired = false; auto itemPosition = view->data()->position(); @@ -952,6 +956,11 @@ int ListWidget::resizeGetHeight(int newWidth) { newHeight += view->height(); } } + if (newHeight > 0) { + _itemAverageHeight = std::max( + itemMinimalHeight(), + newHeight / int(_items.size())); + } _itemsWidth = newWidth; _itemsHeight = newHeight; _itemsTop = (_minHeight > _itemsHeight + st::historyPaddingBottom) ? (_minHeight - _itemsHeight - st::historyPaddingBottom) : 0; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index 6c9e1e107..901889863 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -295,6 +295,7 @@ private: void setTextSelection( not_null view, TextSelection selection); + int itemMinimalHeight() const; bool isGoodForSelection(not_null item) const; bool isGoodForSelection( @@ -393,6 +394,7 @@ private: int _itemsTop = 0; int _itemsWidth = 0; int _itemsHeight = 0; + int _itemAverageHeight = 0; int _minHeight = 0; int _visibleTop = 0;