mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-08 08:04:08 +02:00
Show reply info in scheduled forwards.
This commit is contained in:
parent
45857fe208
commit
5478a8c014
7 changed files with 144 additions and 12 deletions
|
@ -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(); }) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 ¶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<OriginMessage>(¶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(
|
Window::SectionActionResult ScheduledWidget::sendBotCommand(
|
||||||
Bot::SendCommandRequest request) {
|
Bot::SendCommandRequest request) {
|
||||||
if (request.peer != _history->peer) {
|
if (request.peer != _history->peer) {
|
||||||
|
|
|
@ -74,6 +74,10 @@ public:
|
||||||
not_null<Window::SectionMemento*> memento,
|
not_null<Window::SectionMemento*> memento,
|
||||||
const Window::SectionShow ¶ms) override;
|
const Window::SectionShow ¶ms) override;
|
||||||
std::shared_ptr<Window::SectionMemento> createMemento() override;
|
std::shared_ptr<Window::SectionMemento> createMemento() override;
|
||||||
|
bool showMessage(
|
||||||
|
PeerId peerId,
|
||||||
|
const Window::SectionShow ¶ms,
|
||||||
|
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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Reference in a new issue