From 5478a8c014d1dd054f1d7f58b8f288fd2e3d7117 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 13 May 2022 18:54:35 +0400 Subject: [PATCH] Show reply info in scheduled forwards. --- .../data/data_scheduled_messages.cpp | 5 + .../data/data_scheduled_messages.h | 5 +- .../SourceFiles/history/history_message.cpp | 6 +- .../view/history_view_replies_section.cpp | 4 +- .../view/history_view_scheduled_section.cpp | 113 +++++++++++++++++- .../view/history_view_scheduled_section.h | 21 +++- Telegram/SourceFiles/mainwidget.cpp | 2 +- 7 files changed, 144 insertions(+), 12 deletions(-) diff --git a/Telegram/SourceFiles/data/data_scheduled_messages.cpp b/Telegram/SourceFiles/data/data_scheduled_messages.cpp index 0448042bb5..48cfa926ca 100644 --- a/Telegram/SourceFiles/data/data_scheduled_messages.cpp +++ b/Telegram/SourceFiles/data/data_scheduled_messages.cpp @@ -93,6 +93,11 @@ constexpr auto kRequestTimeLimit = 60 * crl::time(1000); } // namespace +bool IsScheduledMsgId(MsgId id) { + return (id > ServerMaxMsgId) + && (id < ServerMaxMsgId + ScheduledMsgIdsRange); +} + ScheduledMessages::ScheduledMessages(not_null owner) : _session(&owner->session()) , _clearTimer([=] { clearOldRequests(); }) { diff --git a/Telegram/SourceFiles/data/data_scheduled_messages.h b/Telegram/SourceFiles/data/data_scheduled_messages.h index b1a3397703..7d546ad1bc 100644 --- a/Telegram/SourceFiles/data/data_scheduled_messages.h +++ b/Telegram/SourceFiles/data/data_scheduled_messages.h @@ -21,6 +21,8 @@ namespace Data { class Session; struct MessagesSlice; +[[nodiscard]] bool IsScheduledMsgId(MsgId id); + class ScheduledMessages final { public: explicit ScheduledMessages(not_null owner); @@ -32,6 +34,7 @@ public: [[nodiscard]] HistoryItem *lookupItem(PeerId peer, MsgId msg) const; [[nodiscard]] HistoryItem *lookupItem(FullMsgId itemId) const; [[nodiscard]] int count(not_null history) const; + [[nodiscard]] MsgId localMessageId(MsgId remoteId) const; void checkEntitiesAndUpdate(const MTPDmessage &data); void apply(const MTPDupdateNewScheduledMessage &update); @@ -81,8 +84,6 @@ private: [[nodiscard]] uint64 countListHash(const List &list) const; void clearOldRequests(); - [[nodiscard]] MsgId localMessageId(MsgId remoteId) const; - const not_null _session; base::Timer _clearTimer; diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 673cea44e1..1480722dcd 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_user.h" #include "data/data_web_page.h" #include "data/data_sponsored_messages.h" +#include "data/data_scheduled_messages.h" #include "styles/style_dialogs.h" #include "styles/style_widgets.h" #include "styles/style_chat.h" @@ -307,7 +308,10 @@ HistoryMessage::HistoryMessage( config.replyToPeer = 0; } } - config.replyTo = data.vreply_to_msg_id().v; + const auto id = data.vreply_to_msg_id().v; + config.replyTo = data.is_reply_to_scheduled() + ? history->owner().scheduledMessages().localMessageId(id) + : id; config.replyToTop = data.vreply_to_top_id().value_or( data.vreply_to_msg_id().v); }); diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 939eed89f0..e61b858f1c 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -1585,9 +1585,7 @@ bool RepliesWidget::showMessage( } return nullptr; }(); - showAtPosition( - Data::MessagePosition{ .fullId = id, .date = message->date() }, - originItem); + showAtPosition(message->position(), originItem); return true; } diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 710e2a8e37..959aab852c 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -41,10 +41,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_peer_menu.h" #include "base/event_filter.h" #include "base/call_delayed.h" +#include "base/qt/qt_key_modifiers.h" #include "core/file_utilities.h" #include "main/main_session.h" #include "data/data_chat_participant_status.h" #include "data/data_session.h" +#include "data/data_changes.h" #include "data/data_scheduled_messages.h" #include "data/data_user.h" #include "data/data_message_reactions.h" @@ -188,6 +190,14 @@ ScheduledWidget::ScheduledWidget( _inner->setEmptyInfoWidget(std::move(emptyInfo)); } + _history->session().changes().messageUpdates( + Data::MessageUpdate::Flag::Destroyed + ) | rpl::start_with_next([=](const Data::MessageUpdate &update) { + while (update.item == _replyReturn) { + calculateNextReplyReturn(); + } + }, lifetime()); + setupScrollDownButton(); setupComposeControls(); } @@ -473,6 +483,47 @@ bool ScheduledWidget::confirmSendingFiles( return confirmSendingFiles(std::move(list), insertTextOnCancel); } +void ScheduledWidget::pushReplyReturn(not_null item) { + if (_inner->viewByPosition(item->position())) { + _replyReturns.push_back(item->id); + } else { + return; + } + _replyReturn = item; + updateScrollDownVisibility(); +} + +void ScheduledWidget::computeCurrentReplyReturn() { + _replyReturn = _replyReturns.empty() + ? nullptr + : _history->owner().message(_history->peer, _replyReturns.back()); +} + +void ScheduledWidget::calculateNextReplyReturn() { + _replyReturn = nullptr; + while (!_replyReturns.empty() && !_replyReturn) { + _replyReturns.pop_back(); + computeCurrentReplyReturn(); + } + if (!_replyReturn) { + updateScrollDownVisibility(); + } +} + +void ScheduledWidget::checkReplyReturns() { + const auto currentTop = _scroll->scrollTop(); + for (; _replyReturn != nullptr; calculateNextReplyReturn()) { + const auto position = _replyReturn->position(); + const auto scrollTop = _inner->scrollTopForPosition(position); + const auto scrolledBelow = scrollTop + ? (currentTop >= std::min(*scrollTop, _scroll->scrollTopMax())) + : _inner->isBelowPosition(position); + if (!scrolledBelow) { + break; + } + } +} + void ScheduledWidget::uploadFile( const QByteArray &fileContent, SendMediaType type) { @@ -803,11 +854,23 @@ void ScheduledWidget::setupScrollDownButton() { } void ScheduledWidget::scrollDownClicked() { + if (base::IsCtrlPressed()) { + showAtEnd(); + } else if (_replyReturn) { + showAtPosition(_replyReturn->position()); + } else { + showAtEnd(); + } +} + +void ScheduledWidget::showAtEnd() { showAtPosition(Data::MaxMessagePosition); } -void ScheduledWidget::showAtPosition(Data::MessagePosition position) { - if (showAtPositionNow(position)) { +void ScheduledWidget::showAtPosition( + Data::MessagePosition position, + HistoryItem *originItem) { + if (showAtPositionNow(position, originItem)) { if (const auto highlight = base::take(_highlightMessageId)) { _inner->highlightMessage(highlight); } @@ -823,8 +886,13 @@ void ScheduledWidget::showAtPosition(Data::MessagePosition position) { } } -bool ScheduledWidget::showAtPositionNow(Data::MessagePosition position) { +bool ScheduledWidget::showAtPositionNow( + Data::MessagePosition position, + HistoryItem *originItem) { if (const auto scrollTop = _inner->scrollTopForPosition(position)) { + while (_replyReturn && position.fullId.msg == _replyReturn->id) { + calculateNextReplyReturn(); + } const auto currentScrollTop = _scroll->scrollTop(); const auto wanted = std::clamp( *scrollTop, @@ -840,6 +908,13 @@ bool ScheduledWidget::showAtPositionNow(Data::MessagePosition position) { (std::abs(fullDelta) > limit ? HistoryView::ListWidget::AnimatedScroll::Part : HistoryView::ListWidget::AnimatedScroll::Full)); + if (position != Data::MaxMessagePosition + && position != Data::UnreadMessagePosition) { + _inner->highlightMessage(position.fullId); + } + if (originItem) { + pushReplyReturn(originItem); + } return true; } return false; @@ -1040,6 +1115,9 @@ void ScheduledWidget::onScroll() { } void ScheduledWidget::updateInnerVisibleArea() { + if (!_inner->animatedScrolling()) { + checkReplyReturns(); + } const auto scrollTop = _scroll->scrollTop(); _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); updateScrollDownVisibility(); @@ -1200,6 +1278,35 @@ bool ScheduledWidget::listIsGoodForAroundPosition( return true; } +bool ScheduledWidget::showMessage( + PeerId peerId, + const Window::SectionShow ¶ms, + MsgId messageId) { + if (peerId != _history->peer->id) { + return false; + } + const auto id = FullMsgId(_history->peer->id, messageId); + const auto message = _history->owner().message(id); + if (!message || !_inner->viewByPosition(message->position())) { + return false; + } + + const auto originItem = [&]() -> HistoryItem* { + using OriginMessage = Window::SectionShow::OriginMessage; + if (const auto origin = std::get_if(¶ms.origin)) { + if (const auto returnTo = session().data().message(origin->id)) { + if (_inner->viewByPosition(returnTo->position()) + && _replyReturn != returnTo) { + return returnTo; + } + } + } + return nullptr; + }(); + showAtPosition(message->position(), originItem); + return true; +} + Window::SectionActionResult ScheduledWidget::sendBotCommand( Bot::SendCommandRequest request) { if (request.peer != _history->peer) { diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h index 1695f3811c..352924dc40 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h @@ -74,6 +74,10 @@ public: not_null memento, const Window::SectionShow ¶ms) override; std::shared_ptr createMemento() override; + bool showMessage( + PeerId peerId, + const Window::SectionShow ¶ms, + MsgId messageId) override; Window::SectionActionResult sendBotCommand( Bot::SendCommandRequest request) override; @@ -141,8 +145,12 @@ private: void updateAdaptiveLayout(); void saveState(not_null memento); void restoreState(not_null memento); - void showAtPosition(Data::MessagePosition position); - bool showAtPositionNow(Data::MessagePosition position); + void showAtPosition( + Data::MessagePosition position, + HistoryItem *originItem = nullptr); + bool showAtPositionNow( + Data::MessagePosition position, + HistoryItem *originItem); void setupComposeControls(); @@ -153,6 +161,7 @@ private: void scrollDownAnimationFinish(); void updateScrollDownVisibility(); void updateScrollDownPosition(); + void showAtEnd(); void confirmSendNowSelected(); void confirmDeleteSelected(); @@ -176,6 +185,11 @@ private: void chooseAttach(); [[nodiscard]] SendMenu::Type sendMenuType() const; + void pushReplyReturn(not_null item); + void computeCurrentReplyReturn(); + void calculateNextReplyReturn(); + void checkReplyReturns(); + void uploadFile(const QByteArray &fileContent, SendMediaType type); bool confirmSendingFiles( QImage &&image, @@ -222,6 +236,9 @@ private: std::unique_ptr _composeControls; bool _skipScrollEvent = false; + std::vector _replyReturns; + HistoryItem *_replyReturn = nullptr; + FullMsgId _highlightMessageId; std::optional _nextAnimatedScrollPosition; int _nextAnimatedScrollDelta = 0; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index f96f51456e..2ddacdf20e 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1307,7 +1307,7 @@ void MainWidget::ui_showPeerHistory( return; } } - if (IsServerMsgId(showAtMsgId) + if ((IsServerMsgId(showAtMsgId) || Data::IsScheduledMsgId(showAtMsgId)) && _mainSection && _mainSection->showMessage(peerId, params, showAtMsgId)) { session().data().hideShownSpoilers();