From 9e434a9136ab2cc4bba0873f25f87463f2392974 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 8 Jan 2026 08:15:09 +0300 Subject: [PATCH] Added initial ability to info list widget to jump to date. --- .../data/data_search_controller.cpp | 74 +++++++++++++++++++ .../SourceFiles/data/data_search_controller.h | 18 +++++ .../info/media/info_media_inner_widget.cpp | 4 + .../info/media/info_media_inner_widget.h | 2 + .../info/media/info_media_list_widget.cpp | 14 ++++ .../info/media/info_media_list_widget.h | 2 + .../info/media/info_media_provider.cpp | 38 ++++++++++ .../info/media/info_media_widget.cpp | 4 + .../info/media/info_media_widget.h | 2 + 9 files changed, 158 insertions(+) diff --git a/Telegram/SourceFiles/data/data_search_controller.cpp b/Telegram/SourceFiles/data/data_search_controller.cpp index 2d01942c56..f5cd92180c 100644 --- a/Telegram/SourceFiles/data/data_search_controller.cpp +++ b/Telegram/SourceFiles/data/data_search_controller.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/data_search_controller.h" +#include "base/unixtime.h" #include "main/main_session.h" #include "data/data_session.h" #include "data/data_messages.h" @@ -334,6 +335,79 @@ HistoryResult ParseHistoryResult( data); } +std::optional PrepareSearchRequestByDate( + not_null peer, + MsgId topicRootId, + PeerId monoforumPeerId, + Storage::SharedMediaType type, + const QDate &date, + Data::LoadDirection direction) { + const auto filter = PrepareSearchFilter(type); + const auto minDate = base::unixtime::serialize( + QDateTime(date, QTime(0, 0))); + const auto maxDate = base::unixtime::serialize( + QDateTime(date.addDays(1), QTime(0, 0))) - 1; + const auto limit = kSharedMediaLimit; + const auto offsetId = 0; + const auto addOffset = 0; + const auto hash = uint64(0); + + using Flag = MTPmessages_Search::Flag; + return MTPmessages_Search( + MTP_flags((topicRootId ? Flag::f_top_msg_id : Flag(0)) + | (monoforumPeerId ? Flag::f_saved_peer_id : Flag(0))), + peer->input(), + MTP_string(""), + MTP_inputPeerEmpty(), + (monoforumPeerId + ? peer->owner().peer(monoforumPeerId)->input() + : MTPInputPeer()), + MTPVector(), + MTP_int(topicRootId), + filter, + MTP_int(minDate), + MTP_int(maxDate), + MTP_int(offsetId), + MTP_int(addOffset), + MTP_int(limit), + MTP_int(0), + MTP_int(0), + MTP_long(hash)); +} + +SearchResultByDate ParseSearchResultByDate( + not_null peer, + const QDate &date, + const SearchResult &parsed) { + const auto targetDate = base::unixtime::serialize( + QDateTime(date, QTime(0, 0))); + auto result = SearchResultByDate(); + if (parsed.messageIds.empty()) { + return result; + } + const auto firstMsgId = parsed.messageIds.front(); + result.first = Data::MessagePosition{ + .fullId = FullMsgId(peer->id, firstMsgId), + .date = TimeId(0), + }; + auto closestMsgId = firstMsgId; + auto minDiff = std::numeric_limits::max(); + for (const auto msgId : parsed.messageIds) { + if (const auto item = peer->owner().message(peer->id, msgId)) { + const auto diff = std::abs(item->date() - targetDate); + if (diff < minDiff) { + minDiff = diff; + closestMsgId = msgId; + } + } + } + result.closestToDate = Data::MessagePosition{ + .fullId = FullMsgId(peer->id, closestMsgId), + .date = TimeId(0), + }; + return result; +} + SearchController::CacheEntry::CacheEntry( not_null session, const Query &query) diff --git a/Telegram/SourceFiles/data/data_search_controller.h b/Telegram/SourceFiles/data/data_search_controller.h index e7fb3f8e9f..a4d5690360 100644 --- a/Telegram/SourceFiles/data/data_search_controller.h +++ b/Telegram/SourceFiles/data/data_search_controller.h @@ -44,6 +44,11 @@ struct GlobalMediaResult { int fullCount = 0; }; +struct SearchResultByDate { + Data::MessagePosition first; + Data::MessagePosition closestToDate; +}; + [[nodiscard]] MTPMessagesFilter PrepareSearchFilter( Storage::SharedMediaType type); @@ -74,6 +79,19 @@ struct GlobalMediaResult { Data::LoadDirection direction, const SearchRequestResult &data); +[[nodiscard]] std::optional PrepareSearchRequestByDate( + not_null peer, + MsgId topicRootId, + PeerId monoforumPeerId, + Storage::SharedMediaType type, + const QDate &date, + Data::LoadDirection direction); + +[[nodiscard]] SearchResultByDate ParseSearchResultByDate( + not_null peer, + const QDate &date, + const SearchResult &parsed); + [[nodiscard]] HistoryRequest PrepareHistoryRequest( not_null peer, MsgId messageId, diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp index 2e6a62506a..b7c983afb4 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp @@ -245,5 +245,9 @@ rpl::producer InnerWidget::scrollToRequests() const { return _scrollToRequests.events(); } +void InnerWidget::jumpToDate(const QDate &date, Fn c) { + _list->jumpToDate(date, std::move(c)); +} + } // namespace Media } // namespace Info diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.h b/Telegram/SourceFiles/info/media/info_media_inner_widget.h index a3e4859603..ff3782f72d 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.h @@ -49,6 +49,8 @@ public: rpl::producer selectedListValue() const; void selectionAction(SelectionAction action); + void jumpToDate(const QDate &date, Fn callback); + ~InnerWidget(); protected: diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 61fd18a36a..6c3085562d 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -2713,5 +2713,19 @@ ListWidget::~ListWidget() { } } +void ListWidget::jumpToDate(const QDate &date, Fn c) { + _provider->jumpToDate(date, [=](FullMsgId fullId) { + const auto item = session().data().message(fullId); + if (!item) { + return; + } + _scrollTopState.position = _provider->scrollTopStatePosition(item); + _scrollTopState.item = item; + if (c) { + c(fullId); + } + }); +} + } // namespace Media } // namespace Info diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index e9e4798fe9..175deb9d30 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -87,6 +87,8 @@ public: void saveState(not_null memento); void restoreState(not_null memento); + void jumpToDate(const QDate &date, Fn callback); + // Overview::Layout::Delegate void registerHeavyItem(not_null item) override; void unregisterHeavyItem(not_null item) override; diff --git a/Telegram/SourceFiles/info/media/info_media_provider.cpp b/Telegram/SourceFiles/info/media/info_media_provider.cpp index 9dcd472654..9ef64abb1a 100644 --- a/Telegram/SourceFiles/info/media/info_media_provider.cpp +++ b/Telegram/SourceFiles/info/media/info_media_provider.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "info/media/info_media_provider.h" +#include "apiwrap.h" #include "info/media/info_media_widget.h" #include "info/media/info_media_list_section.h" #include "info/info_controller.h" @@ -343,6 +344,43 @@ void Provider::setSearchQuery(QString query) { } void Provider::jumpToDate(const QDate &date, Fn callback) { + _viewerLifetime.destroy(); + + const auto peer = _controller->session().data().peer(_peer->id); + const auto request = Api::PrepareSearchRequestByDate( + peer, + _topicRootId, + _monoforumPeerId, + _type, + date, + Data::LoadDirection::Around); + + if (!request) { + return; + } + + _controller->session().api().request( + std::move(*request) + ).done([=](const Api::SearchRequestResult &result) { + const auto byDate = Api::ParseSearchResultByDate( + peer, + date, + Api::ParseSearchResult( + peer, + _type, + 0, + Data::LoadDirection::Around, + result)); + + if (byDate.first) { + _universalAroundId = GetUniversalId(byDate.first.fullId); + if (callback) { + callback(byDate.closestToDate.fullId); + } + _idsLimit = kMinimalIdsLimit * 2; + refreshViewer(); + } + }).send(); } SparseIdsMergedSlice::Key Provider::sliceKey( diff --git a/Telegram/SourceFiles/info/media/info_media_widget.cpp b/Telegram/SourceFiles/info/media/info_media_widget.cpp index 9197c0ae02..8db825f10e 100644 --- a/Telegram/SourceFiles/info/media/info_media_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_widget.cpp @@ -198,4 +198,8 @@ void Widget::restoreState(not_null memento) { _inner->restoreState(memento); } +void Widget::jumpToDate(const QDate &date, Fn c) { + _inner->jumpToDate(date, std::move(c)); +} + } // namespace Info::Media diff --git a/Telegram/SourceFiles/info/media/info_media_widget.h b/Telegram/SourceFiles/info/media/info_media_widget.h index 1a84139190..eb3f8de2cb 100644 --- a/Telegram/SourceFiles/info/media/info_media_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_widget.h @@ -127,6 +127,8 @@ public: rpl::producer title() override; + void jumpToDate(const QDate &date, Fn callback); + private: void saveState(not_null memento); void restoreState(not_null memento);