Show reply info in scheduled forwards.

This commit is contained in:
John Preston 2022-05-13 18:54:35 +04:00
parent 45857fe208
commit 5478a8c014
7 changed files with 144 additions and 12 deletions

View file

@ -93,6 +93,11 @@ constexpr auto kRequestTimeLimit = 60 * crl::time(1000);
} // namespace } // namespace
bool IsScheduledMsgId(MsgId id) {
return (id > ServerMaxMsgId)
&& (id < ServerMaxMsgId + ScheduledMsgIdsRange);
}
ScheduledMessages::ScheduledMessages(not_null<Session*> owner) ScheduledMessages::ScheduledMessages(not_null<Session*> owner)
: _session(&owner->session()) : _session(&owner->session())
, _clearTimer([=] { clearOldRequests(); }) { , _clearTimer([=] { clearOldRequests(); }) {

View file

@ -21,6 +21,8 @@ namespace Data {
class Session; class Session;
struct MessagesSlice; struct MessagesSlice;
[[nodiscard]] bool IsScheduledMsgId(MsgId id);
class ScheduledMessages final { class ScheduledMessages final {
public: public:
explicit ScheduledMessages(not_null<Session*> owner); explicit ScheduledMessages(not_null<Session*> owner);
@ -32,6 +34,7 @@ public:
[[nodiscard]] HistoryItem *lookupItem(PeerId peer, MsgId msg) const; [[nodiscard]] HistoryItem *lookupItem(PeerId peer, MsgId msg) const;
[[nodiscard]] HistoryItem *lookupItem(FullMsgId itemId) const; [[nodiscard]] HistoryItem *lookupItem(FullMsgId itemId) const;
[[nodiscard]] int count(not_null<History*> history) const; [[nodiscard]] int count(not_null<History*> history) const;
[[nodiscard]] MsgId localMessageId(MsgId remoteId) const;
void checkEntitiesAndUpdate(const MTPDmessage &data); void checkEntitiesAndUpdate(const MTPDmessage &data);
void apply(const MTPDupdateNewScheduledMessage &update); void apply(const MTPDupdateNewScheduledMessage &update);
@ -81,8 +84,6 @@ private:
[[nodiscard]] uint64 countListHash(const List &list) const; [[nodiscard]] uint64 countListHash(const List &list) const;
void clearOldRequests(); void clearOldRequests();
[[nodiscard]] MsgId localMessageId(MsgId remoteId) const;
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
base::Timer _clearTimer; base::Timer _clearTimer;

View file

@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_web_page.h" #include "data/data_web_page.h"
#include "data/data_sponsored_messages.h" #include "data/data_sponsored_messages.h"
#include "data/data_scheduled_messages.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
@ -307,7 +308,10 @@ HistoryMessage::HistoryMessage(
config.replyToPeer = 0; 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( config.replyToTop = data.vreply_to_top_id().value_or(
data.vreply_to_msg_id().v); data.vreply_to_msg_id().v);
}); });

View file

@ -1585,9 +1585,7 @@ bool RepliesWidget::showMessage(
} }
return nullptr; return nullptr;
}(); }();
showAtPosition( showAtPosition(message->position(), originItem);
Data::MessagePosition{ .fullId = id, .date = message->date() },
originItem);
return true; return true;
} }

View file

@ -41,10 +41,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_peer_menu.h" #include "window/window_peer_menu.h"
#include "base/event_filter.h" #include "base/event_filter.h"
#include "base/call_delayed.h" #include "base/call_delayed.h"
#include "base/qt/qt_key_modifiers.h"
#include "core/file_utilities.h" #include "core/file_utilities.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "data/data_chat_participant_status.h" #include "data/data_chat_participant_status.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_changes.h"
#include "data/data_scheduled_messages.h" #include "data/data_scheduled_messages.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_message_reactions.h" #include "data/data_message_reactions.h"
@ -188,6 +190,14 @@ ScheduledWidget::ScheduledWidget(
_inner->setEmptyInfoWidget(std::move(emptyInfo)); _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(); setupScrollDownButton();
setupComposeControls(); setupComposeControls();
} }
@ -473,6 +483,47 @@ bool ScheduledWidget::confirmSendingFiles(
return confirmSendingFiles(std::move(list), insertTextOnCancel); return confirmSendingFiles(std::move(list), insertTextOnCancel);
} }
void ScheduledWidget::pushReplyReturn(not_null<HistoryItem*> 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( void ScheduledWidget::uploadFile(
const QByteArray &fileContent, const QByteArray &fileContent,
SendMediaType type) { SendMediaType type) {
@ -803,11 +854,23 @@ void ScheduledWidget::setupScrollDownButton() {
} }
void ScheduledWidget::scrollDownClicked() { void ScheduledWidget::scrollDownClicked() {
if (base::IsCtrlPressed()) {
showAtEnd();
} else if (_replyReturn) {
showAtPosition(_replyReturn->position());
} else {
showAtEnd();
}
}
void ScheduledWidget::showAtEnd() {
showAtPosition(Data::MaxMessagePosition); showAtPosition(Data::MaxMessagePosition);
} }
void ScheduledWidget::showAtPosition(Data::MessagePosition position) { void ScheduledWidget::showAtPosition(
if (showAtPositionNow(position)) { Data::MessagePosition position,
HistoryItem *originItem) {
if (showAtPositionNow(position, originItem)) {
if (const auto highlight = base::take(_highlightMessageId)) { if (const auto highlight = base::take(_highlightMessageId)) {
_inner->highlightMessage(highlight); _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)) { if (const auto scrollTop = _inner->scrollTopForPosition(position)) {
while (_replyReturn && position.fullId.msg == _replyReturn->id) {
calculateNextReplyReturn();
}
const auto currentScrollTop = _scroll->scrollTop(); const auto currentScrollTop = _scroll->scrollTop();
const auto wanted = std::clamp( const auto wanted = std::clamp(
*scrollTop, *scrollTop,
@ -840,6 +908,13 @@ bool ScheduledWidget::showAtPositionNow(Data::MessagePosition position) {
(std::abs(fullDelta) > limit (std::abs(fullDelta) > limit
? HistoryView::ListWidget::AnimatedScroll::Part ? HistoryView::ListWidget::AnimatedScroll::Part
: HistoryView::ListWidget::AnimatedScroll::Full)); : HistoryView::ListWidget::AnimatedScroll::Full));
if (position != Data::MaxMessagePosition
&& position != Data::UnreadMessagePosition) {
_inner->highlightMessage(position.fullId);
}
if (originItem) {
pushReplyReturn(originItem);
}
return true; return true;
} }
return false; return false;
@ -1040,6 +1115,9 @@ void ScheduledWidget::onScroll() {
} }
void ScheduledWidget::updateInnerVisibleArea() { void ScheduledWidget::updateInnerVisibleArea() {
if (!_inner->animatedScrolling()) {
checkReplyReturns();
}
const auto scrollTop = _scroll->scrollTop(); const auto scrollTop = _scroll->scrollTop();
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
updateScrollDownVisibility(); updateScrollDownVisibility();
@ -1200,6 +1278,35 @@ bool ScheduledWidget::listIsGoodForAroundPosition(
return true; return true;
} }
bool ScheduledWidget::showMessage(
PeerId peerId,
const Window::SectionShow &params,
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<OriginMessage>(&params.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( Window::SectionActionResult ScheduledWidget::sendBotCommand(
Bot::SendCommandRequest request) { Bot::SendCommandRequest request) {
if (request.peer != _history->peer) { if (request.peer != _history->peer) {

View file

@ -74,6 +74,10 @@ public:
not_null<Window::SectionMemento*> memento, not_null<Window::SectionMemento*> memento,
const Window::SectionShow &params) override; const Window::SectionShow &params) override;
std::shared_ptr<Window::SectionMemento> createMemento() override; std::shared_ptr<Window::SectionMemento> createMemento() override;
bool showMessage(
PeerId peerId,
const Window::SectionShow &params,
MsgId messageId) override;
Window::SectionActionResult sendBotCommand( Window::SectionActionResult sendBotCommand(
Bot::SendCommandRequest request) override; Bot::SendCommandRequest request) override;
@ -141,8 +145,12 @@ private:
void updateAdaptiveLayout(); void updateAdaptiveLayout();
void saveState(not_null<ScheduledMemento*> memento); void saveState(not_null<ScheduledMemento*> memento);
void restoreState(not_null<ScheduledMemento*> memento); void restoreState(not_null<ScheduledMemento*> memento);
void showAtPosition(Data::MessagePosition position); void showAtPosition(
bool showAtPositionNow(Data::MessagePosition position); Data::MessagePosition position,
HistoryItem *originItem = nullptr);
bool showAtPositionNow(
Data::MessagePosition position,
HistoryItem *originItem);
void setupComposeControls(); void setupComposeControls();
@ -153,6 +161,7 @@ private:
void scrollDownAnimationFinish(); void scrollDownAnimationFinish();
void updateScrollDownVisibility(); void updateScrollDownVisibility();
void updateScrollDownPosition(); void updateScrollDownPosition();
void showAtEnd();
void confirmSendNowSelected(); void confirmSendNowSelected();
void confirmDeleteSelected(); void confirmDeleteSelected();
@ -176,6 +185,11 @@ private:
void chooseAttach(); void chooseAttach();
[[nodiscard]] SendMenu::Type sendMenuType() const; [[nodiscard]] SendMenu::Type sendMenuType() const;
void pushReplyReturn(not_null<HistoryItem*> item);
void computeCurrentReplyReturn();
void calculateNextReplyReturn();
void checkReplyReturns();
void uploadFile(const QByteArray &fileContent, SendMediaType type); void uploadFile(const QByteArray &fileContent, SendMediaType type);
bool confirmSendingFiles( bool confirmSendingFiles(
QImage &&image, QImage &&image,
@ -222,6 +236,9 @@ private:
std::unique_ptr<ComposeControls> _composeControls; std::unique_ptr<ComposeControls> _composeControls;
bool _skipScrollEvent = false; bool _skipScrollEvent = false;
std::vector<MsgId> _replyReturns;
HistoryItem *_replyReturn = nullptr;
FullMsgId _highlightMessageId; FullMsgId _highlightMessageId;
std::optional<Data::MessagePosition> _nextAnimatedScrollPosition; std::optional<Data::MessagePosition> _nextAnimatedScrollPosition;
int _nextAnimatedScrollDelta = 0; int _nextAnimatedScrollDelta = 0;

View file

@ -1307,7 +1307,7 @@ void MainWidget::ui_showPeerHistory(
return; return;
} }
} }
if (IsServerMsgId(showAtMsgId) if ((IsServerMsgId(showAtMsgId) || Data::IsScheduledMsgId(showAtMsgId))
&& _mainSection && _mainSection
&& _mainSection->showMessage(peerId, params, showAtMsgId)) { && _mainSection->showMessage(peerId, params, showAtMsgId)) {
session().data().hideShownSpoilers(); session().data().hideShownSpoilers();