diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 7269188d0..a144c417a 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -3025,6 +3025,24 @@ void InnerWidget::updateRowCornerStatusShown( } } +RowDescriptor InnerWidget::resolveChatNext(RowDescriptor from) const { + const auto row = from.key ? from : _controller->activeChatEntryCurrent(); + return row.key + ? computeJump( + chatListEntryAfter(row), + JumpSkip::NextOrEnd) + : row; +} + +RowDescriptor InnerWidget::resolveChatPrevious(RowDescriptor from) const { + const auto row = from.key ? from : _controller->activeChatEntryCurrent(); + return row.key + ? computeJump( + chatListEntryBefore(row), + JumpSkip::PreviousOrBegin) + : row; +} + void InnerWidget::setupShortcuts() { Shortcuts::Requests( ) | rpl::filter([=] { @@ -3197,7 +3215,7 @@ void InnerWidget::setupShortcuts() { RowDescriptor InnerWidget::computeJump( const RowDescriptor &to, - JumpSkip skip) { + JumpSkip skip) const { auto result = to; if (result.key) { const auto down = (skip == JumpSkip::NextOrEnd) diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 3fb61d03c..101f079e0 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -125,6 +125,9 @@ public: [[nodiscard]] rpl::producer chosenRow() const; [[nodiscard]] rpl::producer<> updated() const; + [[nodiscard]] RowDescriptor resolveChatNext(RowDescriptor from = {}) const; + [[nodiscard]] RowDescriptor resolveChatPrevious(RowDescriptor from = {}) const; + ~InnerWidget(); public Q_SLOTS: @@ -238,7 +241,7 @@ private: void setupShortcuts(); RowDescriptor computeJump( const RowDescriptor &to, - JumpSkip skip); + JumpSkip skip) const; bool jumpToDialogRow(RowDescriptor to); RowDescriptor chatListEntryBefore(const RowDescriptor &which) const; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 4718c0e21..79f6cb38e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1685,6 +1685,14 @@ void Widget::updateForwardBar() { update(); } +RowDescriptor Widget::resolveChatNext(RowDescriptor from) const { + return _inner->resolveChatNext(from); +} + +RowDescriptor Widget::resolveChatPrevious(RowDescriptor from) const { + return _inner->resolveChatPrevious(from); +} + void Widget::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Escape) { if (_openedFolder) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 9942d16eb..dfd9f435e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -91,6 +91,9 @@ public: [[nodiscard]] rpl::producer<> closeForwardBarRequests() const; + [[nodiscard]] RowDescriptor resolveChatNext(RowDescriptor from = {}) const; + [[nodiscard]] RowDescriptor resolveChatPrevious(RowDescriptor from = {}) const; + // Float player interface. bool floatPlayerHandleWheelEvent(QEvent *e) override; QRect floatPlayerAvailableRect() override; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 1d4d78926..ac0552572 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -818,6 +818,13 @@ HistoryWidget::HistoryWidget( } }, lifetime()); + if (session().supportMode()) { + session().data().chatListEntryRefreshes( + ) | rpl::start_with_next([=] { + crl::on_main(this, [=] { checkSupportPreload(true); }); + }, lifetime()); + } + setupScheduledToggle(); setupSendAsToggle(); orderWidgets(); @@ -2299,9 +2306,11 @@ void HistoryWidget::setHistory(History *history) { history->forceFullResize(); } }; + if (_history) { unregisterDraftSources(); clearAllLoadRequests(); + clearSupportPreloadRequest(); const auto wasHistory = base::take(_history); const auto wasMigrated = base::take(_migrated); unloadHeavyViewParts(wasHistory); @@ -2371,6 +2380,16 @@ void HistoryWidget::clearDelayedShowAtRequest() { } } +void HistoryWidget::clearSupportPreloadRequest() { + Expects(_history != nullptr); + + if (_supportPreloadRequest) { + auto &histories = _history->owner().histories(); + histories.cancelRequest(_supportPreloadRequest); + _supportPreloadRequest = 0; + } +} + void HistoryWidget::clearAllLoadRequests() { Expects(_history != nullptr); @@ -2990,6 +3009,9 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages setMsgId(_delayedShowAtMsgId); historyLoaded(); } + if (session().supportMode()) { + crl::on_main(this, [=] { checkSupportPreload(); }); + } } void HistoryWidget::historyLoaded() { @@ -3337,6 +3359,96 @@ void HistoryWidget::preloadHistoryByScroll() { if (scrollTop <= kPreloadHeightsCount * scrollHeight) { loadMessages(); } + if (session().supportMode()) { + crl::on_main(this, [=] { checkSupportPreload(); }); + } +} + +void HistoryWidget::checkSupportPreload(bool force) { + if (!_history + || _firstLoadRequest + || _preloadRequest + || _preloadDownRequest + || (_supportPreloadRequest && !force) + || controller()->activeChatEntryCurrent().key.history() != _history) { + return; + } + + const auto setting = session().settings().supportSwitch(); + const auto command = Support::GetSwitchCommand(setting); + const auto descriptor = !command + ? Dialogs::RowDescriptor() + : (*command == Shortcuts::Command::ChatNext) + ? controller()->resolveChatNext() + : controller()->resolveChatPrevious(); + auto history = descriptor.key.history(); + if (!history || _supportPreloadHistory == history) { + return; + } + clearSupportPreloadRequest(); + _supportPreloadHistory = history; + auto offsetId = MsgId(); + auto offset = 0; + auto loadCount = kMessagesPerPage; + if (const auto around = history->loadAroundId()) { + history->getReadyFor(ShowAtUnreadMsgId); + offset = -loadCount / 2; + offsetId = around; + } + const auto offsetDate = 0; + const auto maxId = 0; + const auto minId = 0; + const auto historyHash = uint64(0); + const auto tmp = history->peer->name.toStdString(); + const auto tmp2 = _history->peer->name.toStdString(); + LOG(("PRELOADING FROM: %1 FOR: %2").arg(_history->peer->name).arg(history->peer->name)); + const auto type = Data::Histories::RequestType::History; + auto &histories = history->owner().histories(); + _supportPreloadRequest = histories.sendRequest(history, type, [=](Fn finish) { + return history->session().api().request(MTPmessages_GetHistory( + history->peer->input, + MTP_int(offsetId), + MTP_int(offsetDate), + MTP_int(offset), + MTP_int(loadCount), + MTP_int(maxId), + MTP_int(minId), + MTP_long(historyHash) + )).done([=](const MTPmessages_Messages &result) { + if (const auto around = history->loadAroundId()) { + if (around != offsetId) { + LOG(("RE-PRELOADING FOR: %1").arg(history->peer->name)); + _supportPreloadRequest = 0; + _supportPreloadHistory = nullptr; + crl::on_main(this, [=] { checkSupportPreload(); }); + return; + } + history->clear(History::ClearType::Unload); + history->getReadyFor(ShowAtUnreadMsgId); + } else if (offsetId) { + LOG(("RE-PRELOADING FOR: %1").arg(history->peer->name)); + _supportPreloadRequest = 0; + _supportPreloadHistory = nullptr; + crl::on_main(this, [=] { checkSupportPreload(); }); + return; + } else { + history->clear(History::ClearType::Unload); + history->getReadyFor(ShowAtTheEndMsgId); + } + LOG(("PRELOADED FOR: %1").arg(history->peer->name)); + auto count = 0; + const QVector emptyList, *histList = &emptyList; + result.match([](const MTPDmessages_messagesNotModified&) { + }, [&](const auto &data) { + history->owner().processUsers(data.vusers()); + history->owner().processChats(data.vchats()); + history->addOlderSlice(data.vmessages().v); + }); + finish(); + }).fail([=](const MTP::Error &error) { + finish(); + }).send(); + }); } void HistoryWidget::checkReplyReturns() { @@ -7534,10 +7646,7 @@ HistoryWidget::~HistoryWidget() { // Saving a draft on account switching. saveFieldToHistoryLocalDraft(); session().api().saveDraftToCloudDelayed(_history); - - clearAllLoadRequests(); setHistory(nullptr); - unregisterDraftSources(); } setTabbedPanel(nullptr); } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 6d5adfdd9..e8cd71b5c 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -234,6 +234,7 @@ public: Ui::ReportReason reason, Fn callback); void clearAllLoadRequests(); + void clearSupportPreloadRequest(); void clearDelayedShowAtRequest(); void clearDelayedShowAt(); void saveFieldToHistoryLocalDraft(); @@ -598,6 +599,7 @@ private: bool readyToForward() const; bool hasSilentToggle() const; + void checkSupportPreload(bool force = false); void handleSupportSwitch(not_null updated); void inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result); @@ -685,6 +687,9 @@ private: MsgId _delayedShowAtMsgId = -1; int _delayedShowAtRequest = 0; // Not real mtpRequestId. + History *_supportPreloadHistory = nullptr; + int _supportPreloadRequest = 0; // Not real mtpRequestId. + object_ptr _topBar; object_ptr _scroll; QPointer _list; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 6229fefa2..a18022cce 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1779,6 +1779,16 @@ bool MainWidget::isThirdSectionShown() const { return _thirdSection != nullptr; } +Dialogs::RowDescriptor MainWidget::resolveChatNext( + Dialogs::RowDescriptor from) const { + return _dialogs ? _dialogs->resolveChatNext(from) : Dialogs::RowDescriptor(); +} + +Dialogs::RowDescriptor MainWidget::resolveChatPrevious( + Dialogs::RowDescriptor from) const { + return _dialogs ? _dialogs->resolveChatPrevious(from) : Dialogs::RowDescriptor(); +} + bool MainWidget::stackIsEmpty() const { return _stack.empty(); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 8b62f2341..9c2e82bb7 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -128,6 +128,11 @@ public: [[nodiscard]] bool isMainSectionShown() const; [[nodiscard]] bool isThirdSectionShown() const; + [[nodiscard]] Dialogs::RowDescriptor resolveChatNext( + Dialogs::RowDescriptor from) const; + [[nodiscard]] Dialogs::RowDescriptor resolveChatPrevious( + Dialogs::RowDescriptor from) const; + void returnTabbedSelector(); void showAnimated(const QPixmap &bgAnimCache, bool back = false); diff --git a/Telegram/SourceFiles/support/support_common.cpp b/Telegram/SourceFiles/support/support_common.cpp index c0d08c2fb..797d7353a 100644 --- a/Telegram/SourceFiles/support/support_common.cpp +++ b/Telegram/SourceFiles/support/support_common.cpp @@ -21,14 +21,19 @@ Qt::KeyboardModifiers SkipSwitchModifiers() { return Qt::ControlModifier | Qt::ShiftModifier; } -FnMut GetSwitchMethod(SwitchSettings value) { +std::optional GetSwitchCommand(SwitchSettings value) { switch (value) { case SwitchSettings::Next: - return Shortcuts::RequestHandler(Shortcuts::Command::ChatNext); + return Shortcuts::Command::ChatNext; case SwitchSettings::Previous: - return Shortcuts::RequestHandler(Shortcuts::Command::ChatPrevious); + return Shortcuts::Command::ChatPrevious; } - return nullptr; + return std::nullopt; +} + +FnMut GetSwitchMethod(SwitchSettings value) { + const auto command = GetSwitchCommand(value); + return command ? Shortcuts::RequestHandler(*command) : nullptr; } } // namespace Support diff --git a/Telegram/SourceFiles/support/support_common.h b/Telegram/SourceFiles/support/support_common.h index 453a28529..c7f1b7edd 100644 --- a/Telegram/SourceFiles/support/support_common.h +++ b/Telegram/SourceFiles/support/support_common.h @@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +namespace Shortcuts { +enum class Command; +} // namespace Shortcuts + namespace Support { enum class SwitchSettings { @@ -15,8 +19,10 @@ enum class SwitchSettings { Previous, }; -Qt::KeyboardModifiers SkipSwitchModifiers(); -bool HandleSwitch(Qt::KeyboardModifiers modifiers); -FnMut GetSwitchMethod(SwitchSettings value); +[[nodiscard]] Qt::KeyboardModifiers SkipSwitchModifiers(); +[[nodiscard]] bool HandleSwitch(Qt::KeyboardModifiers modifiers); +[[nodiscard]] std::optional GetSwitchCommand( + SwitchSettings value); +[[nodiscard]] FnMut GetSwitchMethod(SwitchSettings value); } // namespace Support diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 4e49a1fa9..ab49f8873 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -795,6 +795,16 @@ bool SessionController::jumpToChatListEntry(Dialogs::RowDescriptor row) { return false; } +Dialogs::RowDescriptor SessionController::resolveChatNext( + Dialogs::RowDescriptor from) const { + return content()->resolveChatNext(from); +} + +Dialogs::RowDescriptor SessionController::resolveChatPrevious( + Dialogs::RowDescriptor from) const { + return content()->resolveChatPrevious(from); +} + void SessionController::pushToChatEntryHistory(Dialogs::RowDescriptor row) { if (!_chatEntryHistory.empty() && _chatEntryHistory[_chatEntryHistoryPosition] == row) { diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index da7aaf04c..890e82318 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -301,6 +301,12 @@ public: rpl::producer activeChatEntryValue() const; rpl::producer activeChatValue() const; bool jumpToChatListEntry(Dialogs::RowDescriptor row); + + [[nodiscard]] Dialogs::RowDescriptor resolveChatNext( + Dialogs::RowDescriptor from = {}) const; + [[nodiscard]] Dialogs::RowDescriptor resolveChatPrevious( + Dialogs::RowDescriptor from = {}) const; + void showEditPeerBox(PeerData *peer); void enableGifPauseReason(GifPauseReason reason);