diff --git a/Telegram/SourceFiles/data/data_download_manager.cpp b/Telegram/SourceFiles/data/data_download_manager.cpp index 38d2cc0ff..6a1579c0f 100644 --- a/Telegram/SourceFiles/data/data_download_manager.cpp +++ b/Telegram/SourceFiles/data/data_download_manager.cpp @@ -105,6 +105,25 @@ void DownloadManager::trackSession(not_null session) { }, data.lifetime); } +void DownloadManager::itemVisibilitiesUpdated( + not_null session) { + const auto i = _sessions.find(session); + if (i == end(_sessions) + || i->second.downloading.empty() + || !i->second.downloading.front().hiddenByView) { + return; + } + for (const auto &id : i->second.downloading) { + if (!session->data().queryItemVisibility(id.object.item)) { + for (auto &id : i->second.downloading) { + id.hiddenByView = false; + } + _loadingListChanges.fire({}); + return; + } + } +} + int64 DownloadManager::computeNextStartDate() { const auto now = base::unixtime::now(); if (_lastStartedBase != now) { @@ -140,11 +159,15 @@ void DownloadManager::addLoading(DownloadObject object) { return; } + const auto shownExists = !data.downloading.empty() + && !data.downloading.front().hiddenByView; data.downloading.push_back({ .object = object, .started = computeNextStartDate(), .path = path, .total = size, + .hiddenByView = (!shownExists + && item->history()->owner().queryItemVisibility(item)), }); _loading.emplace(item); _loadingDocuments.emplace(object.document); @@ -908,6 +931,9 @@ rpl::producer MakeDownloadBarContent() { auto content = Ui::DownloadBarContent(); auto single = (const Data::DownloadObject*) nullptr; for (const auto id : manager.loadingList()) { + if (id->hiddenByView) { + break; + } if (!single) { single = &id->object; } diff --git a/Telegram/SourceFiles/data/data_download_manager.h b/Telegram/SourceFiles/data/data_download_manager.h index 6ab00b081..2a1fd8bc8 100644 --- a/Telegram/SourceFiles/data/data_download_manager.h +++ b/Telegram/SourceFiles/data/data_download_manager.h @@ -71,6 +71,7 @@ struct DownloadingId { QString path; int ready = 0; int total = 0; + bool hiddenByView = false; bool done = false; }; @@ -80,6 +81,7 @@ public: ~DownloadManager(); void trackSession(not_null session); + void itemVisibilitiesUpdated(not_null session); [[nodiscard]] DownloadDate computeNextStartDate(); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index e76e655a7..40f13145c 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -44,6 +44,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat.h" #include "data/data_user.h" #include "data/data_file_origin.h" +#include "data/data_download_manager.h" #include "data/data_photo.h" #include "data/data_document.h" #include "data/data_web_page.h" @@ -1373,6 +1374,24 @@ void Session::changeMessageId(PeerId peerId, MsgId wasId, MsgId nowId) { Ensures(ok); } +bool Session::queryItemVisibility(not_null item) const { + auto result = false; + _itemVisibilityQueries.fire({ item, &result }); + return result; +} + +[[nodiscard]] auto Session::itemVisibilityQueries() const +-> rpl::producer { + return _itemVisibilityQueries.events(); +} + +void Session::itemVisibilitiesUpdated() { + // This could be rewritten in a more generic form, like: + // rpl::producer<> itemVisibilitiesUpdates() + // if someone else requires those methods, using fast for now. + Core::App().downloadManager().itemVisibilitiesUpdated(_session); +} + void Session::notifyItemIdChange(IdChange event) { const auto item = event.item; changeMessageId(item->history()->peer->id, event.oldId, item->id); diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index a918edd83..def8eee03 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -227,9 +227,10 @@ public: not_null item; not_null isVisible; }; - [[nodiscard]] base::Observable &queryItemVisibility() { - return _queryItemVisibility; - } + [[nodiscard]] bool queryItemVisibility(not_null item) const; + [[nodiscard]] rpl::producer itemVisibilityQueries() const; + void itemVisibilitiesUpdated(); + struct IdChange { not_null item; MsgId oldId = 0; @@ -839,7 +840,7 @@ private: rpl::event_stream _chatsListChanged; rpl::event_stream> _userIsBotChanges; rpl::event_stream> _botCommandsChanges; - base::Observable _queryItemVisibility; + rpl::event_stream _itemVisibilityQueries; rpl::event_stream _itemIdChanges; rpl::event_stream> _itemLayoutChanges; rpl::event_stream> _viewLayoutChanges; diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index c03749fe0..715985fb8 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -300,20 +300,24 @@ InnerWidget::InnerWidget( } } }, lifetime()); - subscribe(session().data().queryItemVisibility(), [=]( + session().data().itemVisibilityQueries( + ) | rpl::filter([=]( + const Data::Session::ItemVisibilityQuery &query) { + return (_history == query.item->history()) + && query.item->isAdminLogEntry() + && isVisible(); + }) | rpl::start_with_next([=]( const Data::Session::ItemVisibilityQuery &query) { - if (_history != query.item->history() - || !query.item->isAdminLogEntry() - || !isVisible()) { - return; - } if (const auto view = viewForItem(query.item)) { auto top = itemTop(view); - if (top >= 0 && top + view->height() > _visibleTop && top < _visibleBottom) { + if (top >= 0 + && top + view->height() > _visibleTop + && top < _visibleBottom) { *query.isVisible = true; } } - }); + }, lifetime()); + updateEmptyText(); requestAdmins(); @@ -355,6 +359,7 @@ void InnerWidget::visibleTopBottomUpdated( scrollDateHideByTimer(); } _controller->floatPlayerAreaUpdated(); + session().data().itemVisibilitiesUpdated(); } void InnerWidget::updateVisibleTopItem() { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index bf8162baa..922a943f3 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -760,13 +760,15 @@ HistoryWidget::HistoryWidget( updateNotifyControls(); }, lifetime()); - subscribe(session().data().queryItemVisibility(), [=]( + session().data().itemVisibilityQueries( + ) | rpl::filter([=]( + const Data::Session::ItemVisibilityQuery &query) { + return !_a_show.animating() + && (_history == query.item->history()) + && (query.item->mainView() != nullptr) + && isVisible(); + }) | rpl::start_with_next([=]( const Data::Session::ItemVisibilityQuery &query) { - if (_a_show.animating() - || _history != query.item->history() - || !query.item->mainView() || !isVisible()) { - return; - } if (const auto view = query.item->mainView()) { auto top = _list->itemTop(view); if (top >= 0) { @@ -777,7 +779,8 @@ HistoryWidget::HistoryWidget( } } } - }); + }, lifetime()); + _topBar->membersShowAreaActive( ) | rpl::start_with_next([=](bool active) { setMembersShowAreaActive(active); @@ -2301,6 +2304,7 @@ void HistoryWidget::showHistory( } update(); controller()->floatPlayerAreaUpdated(); + session().data().itemVisibilitiesUpdated(); crl::on_main(this, [=] { controller()->widget()->setInnerFocus(); }); } @@ -3332,6 +3336,7 @@ void HistoryWidget::visibleAreaUpdated() { const auto scrollBottom = scrollTop + _scroll->height(); _list->visibleAreaUpdated(scrollTop, scrollBottom); controller()->floatPlayerAreaUpdated(); + session().data().itemVisibilitiesUpdated(); } } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 5e26161d4..a8b9ba2cc 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -331,7 +331,9 @@ ListWidget::ListWidget( itemRemoved(item); }, lifetime()); - subscribe(session().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) { + session().data().itemVisibilityQueries( + ) | rpl::start_with_next([=]( + const Data::Session::ItemVisibilityQuery &query) { if (const auto view = viewForItem(query.item)) { const auto top = itemTop(view); if (top >= 0 @@ -340,7 +342,7 @@ ListWidget::ListWidget( *query.isVisible = true; } } - }); + }, lifetime()); using ChosenReaction = Reactions::Manager::Chosen; _reactionsManager->chosen( @@ -794,6 +796,7 @@ void ListWidget::visibleTopBottomUpdated( scrollDateHideByTimer(); } _controller->floatPlayerAreaUpdated(); + session().data().itemVisibilitiesUpdated(); _applyUpdatedScrollState.call(); } diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 34b384067..6317b2b81 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -169,6 +169,23 @@ void ListWidget::start() { ) | rpl::start_with_next([this] { restart(); }, lifetime()); + + if (_provider->type() == Type::File) { + // For downloads manager. + session().data().itemVisibilityQueries( + ) | rpl::filter([=]( + const Data::Session::ItemVisibilityQuery &query) { + return _provider->isPossiblyMyItem(query.item) + && isVisible(); + }) | rpl::start_with_next([=]( + const Data::Session::ItemVisibilityQuery &query) { + if (const auto found = findItemByItem(query.item)) { + if (itemVisible(found->layout)) { + *query.isVisible = true; + } + } + }, lifetime()); + } } setupSelectRestriction(); @@ -566,6 +583,8 @@ void ListWidget::visibleTopBottomUpdated( _dateBadge->check.call(); } } + + session().data().itemVisibilitiesUpdated(); } void ListWidget::updateDateBadgeFor(int top) { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index a7191cdc4..909cc65a9 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -479,9 +479,7 @@ void MainWidget::floatPlayerEnumerateSections(Fn item) { - auto isVisible = false; - session().data().queryItemVisibility().notify({ item, &isVisible }, true); - return isVisible; + return session().data().queryItemVisibility(item); } void MainWidget::floatPlayerClosed(FullMsgId itemId) {