mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 21:27:07 +02:00
Pass FullReplyTo everywhere.
This commit is contained in:
parent
a77131dfd6
commit
4240568ea5
53 changed files with 964 additions and 744 deletions
|
@ -169,9 +169,7 @@ void SendBotCallbackData(
|
|||
void HideSingleUseKeyboard(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<HistoryItem*> item) {
|
||||
controller->content()->hideSingleUseKeyboard(
|
||||
item->history()->peer,
|
||||
item->id);
|
||||
controller->content()->hideSingleUseKeyboard(item->fullId());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -312,7 +310,9 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
|||
case ButtonType::Default: {
|
||||
// Copy string before passing it to the sending method
|
||||
// because the original button can be destroyed inside.
|
||||
const auto replyTo = item->isRegular() ? item->id : 0;
|
||||
const auto replyTo = item->isRegular()
|
||||
? item->fullId()
|
||||
: FullMsgId();
|
||||
controller->content()->sendBotCommand({
|
||||
.peer = item->history()->peer,
|
||||
.command = QString(button->text),
|
||||
|
@ -363,7 +363,7 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
|||
|
||||
case ButtonType::RequestPhone: {
|
||||
HideSingleUseKeyboard(controller, item);
|
||||
const auto itemId = item->id;
|
||||
const auto itemId = item->fullId();
|
||||
const auto topicRootId = item->topicRootId();
|
||||
const auto history = item->history();
|
||||
controller->show(Ui::MakeConfirmBox({
|
||||
|
@ -376,7 +376,7 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
|||
auto action = Api::SendAction(history);
|
||||
action.clearDraft = false;
|
||||
action.replyTo = {
|
||||
.msgId = itemId,
|
||||
.messageId = itemId,
|
||||
.topicRootId = topicRootId,
|
||||
};
|
||||
history->session().api().shareContact(
|
||||
|
@ -397,13 +397,11 @@ void ActivateBotCommand(ClickHandlerContext context, int row, int column) {
|
|||
chosen |= PollData::Flag::Quiz;
|
||||
}
|
||||
}
|
||||
const auto replyToId = MsgId(0);
|
||||
const auto topicRootId = MsgId(0);
|
||||
const auto replyTo = FullReplyTo();
|
||||
Window::PeerMenuCreatePoll(
|
||||
controller,
|
||||
item->history()->peer,
|
||||
replyToId,
|
||||
topicRootId,
|
||||
replyTo,
|
||||
chosen,
|
||||
disabled);
|
||||
} break;
|
||||
|
|
|
@ -19,8 +19,8 @@ SendAction::SendAction(
|
|||
SendOptions options)
|
||||
: history(thread->owningHistory())
|
||||
, options(options)
|
||||
, replyTo({ .msgId = thread->topicRootId() }) {
|
||||
replyTo.topicRootId = replyTo.msgId;
|
||||
, replyTo({ .messageId = { history->peer->id, thread->topicRootId() } }) {
|
||||
replyTo.topicRootId = replyTo.messageId.msg;
|
||||
}
|
||||
|
||||
SendOptions DefaultSendWhenOnlineOptions() {
|
||||
|
@ -31,7 +31,7 @@ SendOptions DefaultSendWhenOnlineOptions() {
|
|||
}
|
||||
|
||||
MTPInputReplyTo SendAction::mtpReplyTo() const {
|
||||
return Data::ReplyToForMTP(&history->owner(), replyTo);
|
||||
return Data::ReplyToForMTP(history, replyTo);
|
||||
}
|
||||
|
||||
} // namespace Api
|
||||
|
|
|
@ -43,7 +43,7 @@ void Polls::create(
|
|||
|
||||
const auto history = action.history;
|
||||
const auto peer = history->peer;
|
||||
const auto topicRootId = action.replyTo.msgId
|
||||
const auto topicRootId = action.replyTo.messageId
|
||||
? action.replyTo.topicRootId
|
||||
: 0;
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
|
|
|
@ -368,9 +368,9 @@ void SendConfirmedFile(
|
|||
|
||||
if (!isEditing) {
|
||||
const auto histories = &session->data().histories();
|
||||
file->to.replyTo.msgId = histories->convertTopicReplyToId(
|
||||
file->to.replyTo.messageId = histories->convertTopicReplyToId(
|
||||
history,
|
||||
file->to.replyTo.msgId);
|
||||
file->to.replyTo.messageId);
|
||||
file->to.replyTo.topicRootId = histories->convertTopicReplyToId(
|
||||
history,
|
||||
file->to.replyTo.topicRootId);
|
||||
|
|
|
@ -2134,16 +2134,12 @@ void ApiWrap::saveDraftsToCloud() {
|
|||
}
|
||||
|
||||
auto flags = MTPmessages_SaveDraft::Flags(0);
|
||||
auto replyFlags = MTPDinputReplyToMessage::Flags(0);
|
||||
auto &textWithTags = cloudDraft->textWithTags;
|
||||
if (cloudDraft->previewState != Data::PreviewState::Allowed) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_no_webpage;
|
||||
}
|
||||
if (cloudDraft->msgId || cloudDraft->topicRootId) {
|
||||
if (cloudDraft->reply.messageId || cloudDraft->reply.topicRootId) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_reply_to;
|
||||
if (cloudDraft->topicRootId) {
|
||||
replyFlags |= MTPDinputReplyToMessage::Flag::f_top_msg_id;
|
||||
}
|
||||
}
|
||||
if (!textWithTags.tags.isEmpty()) {
|
||||
flags |= MTPmessages_SaveDraft::Flag::f_entities;
|
||||
|
@ -2156,15 +2152,7 @@ void ApiWrap::saveDraftsToCloud() {
|
|||
history->startSavingCloudDraft(topicRootId);
|
||||
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
|
||||
MTP_flags(flags),
|
||||
MTP_inputReplyToMessage(
|
||||
MTP_flags(replyFlags),
|
||||
MTP_int(cloudDraft->msgId
|
||||
? cloudDraft->msgId
|
||||
: cloudDraft->topicRootId),
|
||||
MTP_int(cloudDraft->topicRootId),
|
||||
MTPInputPeer(), // reply_to_peer_id
|
||||
MTPstring(), // quote_text
|
||||
MTPVector<MTPMessageEntity>()), // quote_entities
|
||||
ReplyToForMTP(history, cloudDraft->reply),
|
||||
history->peer->input,
|
||||
MTP_string(textWithTags.text),
|
||||
entities
|
||||
|
@ -3586,9 +3574,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
|||
action.generateLocal = true;
|
||||
sendAction(action);
|
||||
|
||||
const auto replyToId = action.replyTo.msgId;
|
||||
const auto replyTo = replyToId
|
||||
? peer->owner().message(peer, replyToId)
|
||||
const auto replyTo = action.replyTo.messageId
|
||||
? peer->owner().message(action.replyTo.messageId)
|
||||
: nullptr;
|
||||
const auto topicRootId = replyTo
|
||||
? replyTo->topicRootId()
|
||||
|
@ -3789,7 +3776,7 @@ void ApiWrap::sendInlineResult(
|
|||
? (*localMessageId)
|
||||
: _session->data().nextLocalMessageId());
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
const auto topicRootId = action.replyTo.msgId
|
||||
const auto topicRootId = action.replyTo.messageId
|
||||
? action.replyTo.topicRootId
|
||||
: 0;
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ AdminLog::OwnedItem GenerateItem(
|
|||
not_null<HistoryView::ElementDelegate*> delegate,
|
||||
not_null<History*> history,
|
||||
PeerId from,
|
||||
MsgId replyTo,
|
||||
FullMsgId replyTo,
|
||||
const QString &text) {
|
||||
Expects(history->peer->isUser());
|
||||
|
||||
|
@ -81,7 +81,7 @@ AdminLog::OwnedItem GenerateItem(
|
|||
| MessageFlag::HasFromId
|
||||
| MessageFlag::HasReplyInfo),
|
||||
UserId(), // via
|
||||
FullReplyTo{ .msgId = replyTo },
|
||||
FullReplyTo{ .messageId = replyTo },
|
||||
base::unixtime::now(), // date
|
||||
from,
|
||||
QString(), // postAuthor
|
||||
|
@ -143,13 +143,13 @@ void AddMessage(
|
|||
GenerateUser(
|
||||
history,
|
||||
tr::lng_settings_chat_message_reply_from(tr::now)),
|
||||
0,
|
||||
FullMsgId(),
|
||||
tr::lng_settings_chat_message_reply(tr::now));
|
||||
auto message = GenerateItem(
|
||||
state->delegate.get(),
|
||||
history,
|
||||
history->peer->id,
|
||||
state->reply->data()->fullId().msg,
|
||||
state->reply->data()->fullId(),
|
||||
tr::lng_settings_chat_message(tr::now));
|
||||
const auto view = message.get();
|
||||
state->item = std::move(message);
|
||||
|
|
|
@ -16,7 +16,7 @@ struct SendCommandRequest {
|
|||
not_null<PeerData*> peer;
|
||||
QString command;
|
||||
FullMsgId context;
|
||||
MsgId replyTo = 0;
|
||||
FullReplyTo replyTo;
|
||||
};
|
||||
|
||||
[[nodiscard]] QString WrapCommandInChat(
|
||||
|
|
|
@ -308,7 +308,6 @@ void BotCommandClickHandler::onClick(ClickContext context) const {
|
|||
.peer = peer,
|
||||
.command = _cmd,
|
||||
.context = my.itemId,
|
||||
.replyTo = 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/message_field.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_widget.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "mainwidget.h"
|
||||
|
@ -21,14 +22,12 @@ namespace Data {
|
|||
|
||||
Draft::Draft(
|
||||
const TextWithTags &textWithTags,
|
||||
MsgId msgId,
|
||||
MsgId topicRootId,
|
||||
FullReplyTo reply,
|
||||
const MessageCursor &cursor,
|
||||
PreviewState previewState,
|
||||
mtpRequestId saveRequestId)
|
||||
: textWithTags(textWithTags)
|
||||
, msgId(msgId)
|
||||
, topicRootId(topicRootId)
|
||||
, reply(std::move(reply))
|
||||
, cursor(cursor)
|
||||
, previewState(previewState)
|
||||
, saveRequestId(saveRequestId) {
|
||||
|
@ -36,13 +35,11 @@ Draft::Draft(
|
|||
|
||||
Draft::Draft(
|
||||
not_null<const Ui::InputField*> field,
|
||||
MsgId msgId,
|
||||
MsgId topicRootId,
|
||||
FullReplyTo reply,
|
||||
PreviewState previewState,
|
||||
mtpRequestId saveRequestId)
|
||||
: textWithTags(field->getTextWithTags())
|
||||
, msgId(msgId)
|
||||
, topicRootId(topicRootId)
|
||||
, reply(std::move(reply))
|
||||
, cursor(field)
|
||||
, previewState(previewState) {
|
||||
}
|
||||
|
@ -64,22 +61,26 @@ void ApplyPeerCloudDraft(
|
|||
session,
|
||||
draft.ventities().value_or_empty()))
|
||||
};
|
||||
auto replyTo = MsgId();
|
||||
if (const auto reply = draft.vreply_to()) {
|
||||
reply->match([&](const MTPDmessageReplyHeader &data) {
|
||||
if (!data.vreply_to_peer_id()
|
||||
|| (peerFromMTP(*data.vreply_to_peer_id()) == peerId)) {
|
||||
replyTo = data.vreply_to_msg_id().value_or_empty();
|
||||
} else {
|
||||
// #TODO replies
|
||||
}
|
||||
}, [&](const MTPDmessageReplyStoryHeader &data) {
|
||||
});
|
||||
}
|
||||
const auto reply = draft.vreply_to()
|
||||
? ReplyFieldsFromMTP(history, *draft.vreply_to())
|
||||
: ReplyFields();
|
||||
const auto replyPeerId = reply.externalPeerId
|
||||
? reply.externalPeerId
|
||||
: peerId;
|
||||
auto cloudDraft = std::make_unique<Draft>(
|
||||
textWithTags,
|
||||
replyTo,
|
||||
topicRootId,
|
||||
FullReplyTo{
|
||||
.messageId = FullMsgId(replyPeerId, reply.messageId),
|
||||
.quote = TextWithTags{
|
||||
reply.quote.text,
|
||||
TextUtilities::ConvertEntitiesToTextTags(
|
||||
reply.quote.entities),
|
||||
},
|
||||
.storyId = (reply.storyId
|
||||
? FullStoryId(replyPeerId, reply.storyId)
|
||||
: FullStoryId()),
|
||||
.topicRootId = topicRootId,
|
||||
},
|
||||
MessageCursor(Ui::kQFixedMax, Ui::kQFixedMax, Ui::kQFixedMax),
|
||||
(draft.is_no_webpage()
|
||||
? Data::PreviewState::Cancelled
|
||||
|
|
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "data/data_msg_id.h"
|
||||
|
||||
namespace Ui {
|
||||
class InputField;
|
||||
} // namespace Ui
|
||||
|
@ -38,22 +40,19 @@ struct Draft {
|
|||
Draft() = default;
|
||||
Draft(
|
||||
const TextWithTags &textWithTags,
|
||||
MsgId msgId,
|
||||
MsgId topicRootId,
|
||||
FullReplyTo reply,
|
||||
const MessageCursor &cursor,
|
||||
PreviewState previewState,
|
||||
mtpRequestId saveRequestId = 0);
|
||||
Draft(
|
||||
not_null<const Ui::InputField*> field,
|
||||
MsgId msgId,
|
||||
MsgId topicRootId,
|
||||
FullReplyTo reply,
|
||||
PreviewState previewState,
|
||||
mtpRequestId saveRequestId = 0);
|
||||
|
||||
TimeId date = 0;
|
||||
TextWithTags textWithTags;
|
||||
MsgId msgId = 0; // replyToId for message draft, editMsgId for edit draft
|
||||
MsgId topicRootId = 0;
|
||||
FullReplyTo reply; // reply.messageId.msg is editMsgId for edit draft.
|
||||
MessageCursor cursor;
|
||||
PreviewState previewState = PreviewState::Allowed;
|
||||
mtpRequestId saveRequestId = 0;
|
||||
|
@ -167,7 +166,8 @@ using HistoryDrafts = base::flat_map<DraftKey, std::unique_ptr<Draft>>;
|
|||
|
||||
[[nodiscard]] inline bool DraftIsNull(const Draft *draft) {
|
||||
return !draft
|
||||
|| (!draft->msgId && DraftStringIsEmpty(draft->textWithTags.text));
|
||||
|| (!draft->reply.messageId
|
||||
&& DraftStringIsEmpty(draft->textWithTags.text));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool DraftsAreEqual(const Draft *a, const Draft *b) {
|
||||
|
@ -179,7 +179,7 @@ using HistoryDrafts = base::flat_map<DraftKey, std::unique_ptr<Draft>>;
|
|||
return false;
|
||||
}
|
||||
return (a->textWithTags == b->textWithTags)
|
||||
&& (a->msgId == b->msgId)
|
||||
&& (a->reply == b->reply)
|
||||
&& (a->previewState == b->previewState);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,8 +33,9 @@ constexpr auto kReadRequestTimeout = 3 * crl::time(1000);
|
|||
} // namespace
|
||||
|
||||
MTPInputReplyTo ReplyToForMTP(
|
||||
not_null<Session*> owner,
|
||||
not_null<History*> history,
|
||||
FullReplyTo replyTo) {
|
||||
const auto owner = &history->owner();
|
||||
if (replyTo.storyId) {
|
||||
if (const auto peer = owner->peerLoaded(replyTo.storyId.peer)) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
|
@ -43,15 +44,19 @@ MTPInputReplyTo ReplyToForMTP(
|
|||
MTP_int(replyTo.storyId.story));
|
||||
}
|
||||
}
|
||||
} else if (replyTo.msgId || replyTo.topicRootId) {
|
||||
} else if (replyTo.messageId || replyTo.topicRootId) {
|
||||
const auto external = (replyTo.messageId.peer != history->peer->id);
|
||||
using Flag = MTPDinputReplyToMessage::Flag;
|
||||
return MTP_inputReplyToMessage( // #TODO replies
|
||||
(replyTo.topicRootId
|
||||
? MTP_flags(Flag::f_top_msg_id)
|
||||
: MTP_flags(0)),
|
||||
MTP_int(replyTo.msgId ? replyTo.msgId : replyTo.topicRootId),
|
||||
return MTP_inputReplyToMessage(
|
||||
MTP_flags((replyTo.topicRootId ? Flag::f_top_msg_id : Flag())
|
||||
| (external ? Flag::f_reply_to_peer_id : Flag())),
|
||||
MTP_int(replyTo.messageId
|
||||
? replyTo.messageId.msg
|
||||
: replyTo.topicRootId),
|
||||
MTP_int(replyTo.topicRootId),
|
||||
MTPInputPeer(), // reply_to_peer_id
|
||||
(external
|
||||
? owner->peer(replyTo.messageId.peer)->input
|
||||
: MTPInputPeer()),
|
||||
MTPstring(), // quote_text
|
||||
MTPVector<MTPMessageEntity>()); // quote_entities
|
||||
}
|
||||
|
@ -914,7 +919,7 @@ int Histories::sendPreparedMessage(
|
|||
not_null<History*> history,
|
||||
FullReplyTo replyTo,
|
||||
uint64 randomId,
|
||||
Fn<PreparedMessage(not_null<Session*>, FullReplyTo)> message,
|
||||
Fn<PreparedMessage(not_null<History*>, FullReplyTo)> message,
|
||||
Fn<void(const MTPUpdates&, const MTP::Response&)> done,
|
||||
Fn<void(const MTP::Error&, const MTP::Response&)> fail) {
|
||||
if (isCreatingTopic(history, replyTo.topicRootId)) {
|
||||
|
@ -929,7 +934,7 @@ int Histories::sendPreparedMessage(
|
|||
}
|
||||
i->second.push_back({
|
||||
.randomId = randomId,
|
||||
.replyTo = replyTo.msgId,
|
||||
.replyTo = replyTo.messageId,
|
||||
.message = std::move(message),
|
||||
.done = std::move(done),
|
||||
.fail = std::move(fail),
|
||||
|
@ -939,11 +944,11 @@ int Histories::sendPreparedMessage(
|
|||
return id;
|
||||
}
|
||||
const auto realReplyTo = FullReplyTo{
|
||||
.msgId = convertTopicReplyToId(history, replyTo.msgId),
|
||||
.topicRootId = convertTopicReplyToId(history, replyTo.topicRootId),
|
||||
.messageId = convertTopicReplyToId(history, replyTo.messageId),
|
||||
.storyId = replyTo.storyId,
|
||||
.topicRootId = convertTopicReplyToId(history, replyTo.topicRootId),
|
||||
};
|
||||
return v::match(message(_owner, realReplyTo), [&](const auto &request) {
|
||||
return v::match(message(history, realReplyTo), [&](const auto &request) {
|
||||
const auto type = RequestType::Send;
|
||||
return sendRequest(history, type, [=](Fn<void()> finish) {
|
||||
const auto session = &_owner->session();
|
||||
|
@ -987,7 +992,7 @@ void Histories::checkTopicCreated(FullMsgId rootId, MsgId realRoot) {
|
|||
sendPreparedMessage(
|
||||
history,
|
||||
FullReplyTo{
|
||||
.msgId = entry.replyTo,
|
||||
.messageId = entry.replyTo,
|
||||
.topicRootId = realRoot,
|
||||
},
|
||||
entry.randomId,
|
||||
|
@ -1009,6 +1014,15 @@ void Histories::checkTopicCreated(FullMsgId rootId, MsgId realRoot) {
|
|||
}
|
||||
}
|
||||
|
||||
FullMsgId Histories::convertTopicReplyToId(
|
||||
not_null<History*> history,
|
||||
FullMsgId replyToId) const {
|
||||
const auto id = (history->peer->id == replyToId.peer)
|
||||
? convertTopicReplyToId(history, replyToId.msg)
|
||||
: replyToId.msg;
|
||||
return { replyToId.peer, id };
|
||||
}
|
||||
|
||||
MsgId Histories::convertTopicReplyToId(
|
||||
not_null<History*> history,
|
||||
MsgId replyToId) const {
|
||||
|
|
|
@ -27,7 +27,7 @@ class Session;
|
|||
class Folder;
|
||||
|
||||
[[nodiscard]] MTPInputReplyTo ReplyToForMTP(
|
||||
not_null<Session*> owner,
|
||||
not_null<History*> history,
|
||||
FullReplyTo replyTo);
|
||||
|
||||
class Histories final {
|
||||
|
@ -108,7 +108,7 @@ public:
|
|||
not_null<History*> history,
|
||||
FullReplyTo replyTo,
|
||||
uint64 randomId,
|
||||
Fn<PreparedMessage(not_null<Session*>, FullReplyTo)> message,
|
||||
Fn<PreparedMessage(not_null<History*>, FullReplyTo)> message,
|
||||
Fn<void(const MTPUpdates&, const MTP::Response&)> done,
|
||||
Fn<void(const MTP::Error&, const MTP::Response&)> fail);
|
||||
|
||||
|
@ -116,14 +116,17 @@ public:
|
|||
};
|
||||
template <typename RequestType, typename ...Args>
|
||||
static auto PrepareMessage(const Args &...args)
|
||||
-> Fn<Histories::PreparedMessage(not_null<Session*>, FullReplyTo)> {
|
||||
return [=](not_null<Session*> owner, FullReplyTo replyTo)
|
||||
-> Fn<Histories::PreparedMessage(not_null<History*>, FullReplyTo)> {
|
||||
return [=](not_null<History*> history, FullReplyTo replyTo)
|
||||
-> RequestType {
|
||||
return { ReplaceReplyIds(owner, args, replyTo)... };
|
||||
return { ReplaceReplyIds(history, args, replyTo)... };
|
||||
};
|
||||
}
|
||||
|
||||
void checkTopicCreated(FullMsgId rootId, MsgId realRoot);
|
||||
[[nodiscard]] FullMsgId convertTopicReplyToId(
|
||||
not_null<History*> history,
|
||||
FullMsgId replyToId) const;
|
||||
[[nodiscard]] MsgId convertTopicReplyToId(
|
||||
not_null<History*> history,
|
||||
MsgId replyToId) const;
|
||||
|
@ -152,8 +155,8 @@ private:
|
|||
};
|
||||
struct DelayedByTopicMessage {
|
||||
uint64 randomId = 0;
|
||||
MsgId replyTo = 0;
|
||||
Fn<PreparedMessage(not_null<Session*>, FullReplyTo)> message;
|
||||
FullMsgId replyTo;
|
||||
Fn<PreparedMessage(not_null<History*>, FullReplyTo)> message;
|
||||
Fn<void(const MTPUpdates&, const MTP::Response&)> done;
|
||||
Fn<void(const MTP::Error&, const MTP::Response&)> fail;
|
||||
int requestId = 0;
|
||||
|
@ -169,11 +172,11 @@ private:
|
|||
|
||||
template <typename Arg>
|
||||
static auto ReplaceReplyIds(
|
||||
not_null<Session*> owner,
|
||||
not_null<History*> history,
|
||||
Arg arg,
|
||||
FullReplyTo replyTo) {
|
||||
if constexpr (std::is_same_v<Arg, ReplyToPlaceholder>) {
|
||||
return ReplyToForMTP(owner, replyTo);
|
||||
return ReplyToForMTP(history, replyTo);
|
||||
} else {
|
||||
return arg;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include "data/data_peer_id.h"
|
||||
#include "ui/text/text_entity.h"
|
||||
|
||||
struct MsgId {
|
||||
constexpr MsgId() noexcept = default;
|
||||
|
@ -67,21 +68,6 @@ struct FullStoryId {
|
|||
friend inline bool operator==(FullStoryId, FullStoryId) = default;
|
||||
};
|
||||
|
||||
struct FullReplyTo {
|
||||
MsgId msgId = 0;
|
||||
MsgId topicRootId = 0;
|
||||
FullStoryId storyId;
|
||||
|
||||
[[nodiscard]] bool valid() const {
|
||||
return msgId || (storyId && peerIsUser(storyId.peer));
|
||||
}
|
||||
explicit operator bool() const {
|
||||
return valid();
|
||||
}
|
||||
friend inline auto operator<=>(FullReplyTo, FullReplyTo) = default;
|
||||
friend inline bool operator==(FullReplyTo, FullReplyTo) = default;
|
||||
};
|
||||
|
||||
constexpr auto StartClientMsgId = MsgId(0x01 - (1LL << 58));
|
||||
constexpr auto ClientMsgIds = (1LL << 31);
|
||||
constexpr auto EndClientMsgId = MsgId(StartClientMsgId.bare + ClientMsgIds);
|
||||
|
@ -169,6 +155,22 @@ struct FullMsgId {
|
|||
|
||||
Q_DECLARE_METATYPE(FullMsgId);
|
||||
|
||||
struct FullReplyTo {
|
||||
FullMsgId messageId;
|
||||
TextWithTags quote;
|
||||
FullStoryId storyId;
|
||||
MsgId topicRootId = 0;
|
||||
|
||||
[[nodiscard]] bool valid() const {
|
||||
return messageId || (storyId && peerIsUser(storyId.peer));
|
||||
}
|
||||
explicit operator bool() const {
|
||||
return valid();
|
||||
}
|
||||
friend inline auto operator<=>(FullReplyTo, FullReplyTo) = default;
|
||||
friend inline bool operator==(FullReplyTo, FullReplyTo) = default;
|
||||
};
|
||||
|
||||
struct GlobalMsgId {
|
||||
FullMsgId itemId;
|
||||
uint64 sessionUniqueId = 0;
|
||||
|
|
|
@ -108,8 +108,7 @@ struct EntryState {
|
|||
Key key;
|
||||
Section section = Section::History;
|
||||
FilterId filterId = 0;
|
||||
MsgId rootId = 0;
|
||||
MsgId currentReplyToId = 0;
|
||||
FullReplyTo currentReplyTo;
|
||||
|
||||
friend inline constexpr auto operator<=>(EntryState, EntryState) noexcept
|
||||
= default;
|
||||
|
|
|
@ -659,7 +659,7 @@ not_null<Ui::PathShiftGradient*> InnerWidget::elementPathShiftGradient() {
|
|||
return _pathGradient.get();
|
||||
}
|
||||
|
||||
void InnerWidget::elementReplyTo(const FullMsgId &to) {
|
||||
void InnerWidget::elementReplyTo(const FullReplyTo &to) {
|
||||
}
|
||||
|
||||
void InnerWidget::elementStartInteraction(not_null<const Element*> view) {
|
||||
|
|
|
@ -127,7 +127,7 @@ public:
|
|||
void elementHandleViaClick(not_null<UserData*> bot) override;
|
||||
bool elementIsChatWide() override;
|
||||
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
|
||||
void elementReplyTo(const FullMsgId &to) override;
|
||||
void elementReplyTo(const FullReplyTo &to) override;
|
||||
void elementStartInteraction(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
void elementStartPremium(
|
||||
|
|
|
@ -177,8 +177,7 @@ void History::takeLocalDraft(not_null<History*> from) {
|
|||
&& !_drafts.contains(Data::DraftKey::Local(topicRootId))) {
|
||||
// Edit and reply to drafts can't migrate.
|
||||
// Cloud drafts do not migrate automatically.
|
||||
draft->msgId = 0;
|
||||
|
||||
draft->reply = FullReplyTo();
|
||||
setLocalDraft(std::move(draft));
|
||||
}
|
||||
from->clearLocalDraft(topicRootId);
|
||||
|
@ -194,6 +193,7 @@ void History::createLocalDraftFromCloud(MsgId topicRootId) {
|
|||
return;
|
||||
}
|
||||
|
||||
draft->reply.topicRootId = topicRootId;
|
||||
auto existing = localDraft(topicRootId);
|
||||
if (Data::DraftIsNull(existing)
|
||||
|| !existing->date
|
||||
|
@ -201,15 +201,13 @@ void History::createLocalDraftFromCloud(MsgId topicRootId) {
|
|||
if (!existing) {
|
||||
setLocalDraft(std::make_unique<Data::Draft>(
|
||||
draft->textWithTags,
|
||||
draft->msgId,
|
||||
topicRootId,
|
||||
draft->reply,
|
||||
draft->cursor,
|
||||
draft->previewState));
|
||||
existing = localDraft(topicRootId);
|
||||
} else if (existing != draft) {
|
||||
existing->textWithTags = draft->textWithTags;
|
||||
existing->msgId = draft->msgId;
|
||||
existing->topicRootId = draft->topicRootId;
|
||||
existing->reply = draft->reply;
|
||||
existing->cursor = draft->cursor;
|
||||
existing->previewState = draft->previewState;
|
||||
}
|
||||
|
@ -277,8 +275,7 @@ Data::Draft *History::createCloudDraft(
|
|||
if (Data::DraftIsNull(fromDraft)) {
|
||||
setCloudDraft(std::make_unique<Data::Draft>(
|
||||
TextWithTags(),
|
||||
0,
|
||||
topicRootId,
|
||||
FullReplyTo(),
|
||||
MessageCursor(),
|
||||
Data::PreviewState::Allowed));
|
||||
cloudDraft(topicRootId)->date = TimeId(0);
|
||||
|
@ -287,18 +284,18 @@ Data::Draft *History::createCloudDraft(
|
|||
if (!existing) {
|
||||
setCloudDraft(std::make_unique<Data::Draft>(
|
||||
fromDraft->textWithTags,
|
||||
fromDraft->msgId,
|
||||
topicRootId,
|
||||
fromDraft->reply,
|
||||
fromDraft->cursor,
|
||||
fromDraft->previewState));
|
||||
existing = cloudDraft(topicRootId);
|
||||
} else if (existing != fromDraft) {
|
||||
existing->textWithTags = fromDraft->textWithTags;
|
||||
existing->msgId = fromDraft->msgId;
|
||||
existing->reply = fromDraft->reply;
|
||||
existing->cursor = fromDraft->cursor;
|
||||
existing->previewState = fromDraft->previewState;
|
||||
}
|
||||
existing->date = base::unixtime::now();
|
||||
existing->reply.topicRootId = topicRootId;
|
||||
}
|
||||
|
||||
if (const auto thread = threadFor(topicRootId)) {
|
||||
|
|
|
@ -329,17 +329,17 @@ public:
|
|||
}
|
||||
void setLocalDraft(std::unique_ptr<Data::Draft> &&draft) {
|
||||
setDraft(
|
||||
Data::DraftKey::Local(draft->topicRootId),
|
||||
Data::DraftKey::Local(draft->reply.topicRootId),
|
||||
std::move(draft));
|
||||
}
|
||||
void setLocalEditDraft(std::unique_ptr<Data::Draft> &&draft) {
|
||||
setDraft(
|
||||
Data::DraftKey::LocalEdit(draft->topicRootId),
|
||||
Data::DraftKey::LocalEdit(draft->reply.topicRootId),
|
||||
std::move(draft));
|
||||
}
|
||||
void setCloudDraft(std::unique_ptr<Data::Draft> &&draft) {
|
||||
setDraft(
|
||||
Data::DraftKey::Cloud(draft->topicRootId),
|
||||
Data::DraftKey::Cloud(draft->reply.topicRootId),
|
||||
std::move(draft));
|
||||
}
|
||||
void clearLocalDraft(MsgId topicRootId) {
|
||||
|
|
|
@ -287,7 +287,7 @@ public:
|
|||
|
||||
return _widget->elementPathShiftGradient();
|
||||
}
|
||||
void elementReplyTo(const FullMsgId &to) override {
|
||||
void elementReplyTo(const FullReplyTo &to) override {
|
||||
if (_widget) {
|
||||
_widget->elementReplyTo(to);
|
||||
}
|
||||
|
@ -2206,7 +2206,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
}();
|
||||
if (canReply) {
|
||||
_menu->addAction(tr::lng_context_reply_msg(tr::now), [=] {
|
||||
_widget->replyToMessage(itemId);
|
||||
_widget->replyToMessage({ itemId });
|
||||
}, &st::menuIconReply);
|
||||
}
|
||||
const auto repliesCount = item->repliesCount();
|
||||
|
@ -3481,7 +3481,7 @@ not_null<Ui::PathShiftGradient*> HistoryInner::elementPathShiftGradient() {
|
|||
return _pathGradient.get();
|
||||
}
|
||||
|
||||
void HistoryInner::elementReplyTo(const FullMsgId &to) {
|
||||
void HistoryInner::elementReplyTo(const FullReplyTo &to) {
|
||||
return _widget->replyToMessage(to);
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ public:
|
|||
void elementHandleViaClick(not_null<UserData*> bot);
|
||||
bool elementIsChatWide();
|
||||
not_null<Ui::PathShiftGradient*> elementPathShiftGradient();
|
||||
void elementReplyTo(const FullMsgId &to);
|
||||
void elementReplyTo(const FullReplyTo &to);
|
||||
void elementStartInteraction(not_null<const Element*> view);
|
||||
void elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
|
|
|
@ -125,23 +125,23 @@ void HistoryItem::HistoryItem::Destroyer::operator()(HistoryItem *value) {
|
|||
}
|
||||
|
||||
struct HistoryItem::CreateConfig {
|
||||
PeerId replyToPeer = 0;
|
||||
MsgId replyTo = 0;
|
||||
MsgId replyToTop = 0;
|
||||
StoryId replyToStory = 0;
|
||||
bool replyIsTopicPost = false;
|
||||
ReplyFields reply;
|
||||
|
||||
UserId viaBotId = 0;
|
||||
int viewsCount = -1;
|
||||
int forwardsCount = -1;
|
||||
QString author;
|
||||
PeerId senderOriginal = 0;
|
||||
QString senderNameOriginal;
|
||||
QString forwardPsaType;
|
||||
QString postAuthor;
|
||||
|
||||
MsgId originalId = 0;
|
||||
TimeId originalDate = 0;
|
||||
PeerId originalSenderId = 0;
|
||||
QString originalSenderName;
|
||||
QString originalPostAuthor;
|
||||
|
||||
QString forwardPsaType;
|
||||
PeerId savedFromPeer = 0;
|
||||
MsgId savedFromMsgId = 0;
|
||||
QString authorOriginal;
|
||||
TimeId originalDate = 0;
|
||||
|
||||
TimeId editDate = 0;
|
||||
HistoryMessageMarkupData markup;
|
||||
HistoryMessageRepliesData replies;
|
||||
|
@ -154,14 +154,14 @@ struct HistoryItem::CreateConfig {
|
|||
void HistoryItem::FillForwardedInfo(
|
||||
CreateConfig &config,
|
||||
const MTPDmessageFwdHeader &data) {
|
||||
if (const auto fromId = data.vfrom_id()) {
|
||||
config.senderOriginal = peerFromMTP(*fromId);
|
||||
}
|
||||
config.originalDate = data.vdate().v;
|
||||
config.senderNameOriginal = qs(data.vfrom_name().value_or_empty());
|
||||
config.forwardPsaType = qs(data.vpsa_type().value_or_empty());
|
||||
config.originalId = data.vchannel_post().value_or_empty();
|
||||
config.authorOriginal = qs(data.vpost_author().value_or_empty());
|
||||
config.originalDate = data.vdate().v;
|
||||
if (const auto fromId = data.vfrom_id()) {
|
||||
config.originalSenderId = peerFromMTP(*fromId);
|
||||
}
|
||||
config.originalSenderName = qs(data.vfrom_name().value_or_empty());
|
||||
config.originalPostAuthor = qs(data.vpost_author().value_or_empty());
|
||||
config.forwardPsaType = qs(data.vpsa_type().value_or_empty());
|
||||
const auto savedFromPeer = data.vsaved_from_peer();
|
||||
const auto savedFromMsgId = data.vsaved_from_msg_id();
|
||||
if (savedFromPeer && savedFromMsgId) {
|
||||
|
@ -435,21 +435,21 @@ HistoryItem::HistoryItem(
|
|||
|
||||
const auto originalMedia = original->media();
|
||||
const auto dropForwardInfo = original->computeDropForwardedInfo();
|
||||
config.replyTo = config.replyToTop = topicRootId;
|
||||
config.replyIsTopicPost = (topicRootId != 0);
|
||||
config.reply.messageId = config.reply.topMessageId = topicRootId;
|
||||
config.reply.topicPost = (topicRootId != 0);
|
||||
if (!dropForwardInfo) {
|
||||
config.originalDate = original->dateOriginal();
|
||||
config.originalDate = original->originalDate();
|
||||
if (const auto info = original->hiddenSenderInfo()) {
|
||||
config.senderNameOriginal = info->name;
|
||||
} else if (const auto senderOriginal = original->senderOriginal()) {
|
||||
config.senderOriginal = senderOriginal->id;
|
||||
if (senderOriginal->isChannel()) {
|
||||
config.originalId = original->idOriginal();
|
||||
config.originalSenderName = info->name;
|
||||
} else if (const auto originalSender = original->originalSender()) {
|
||||
config.originalSenderId = originalSender->id;
|
||||
if (originalSender->isChannel()) {
|
||||
config.originalId = original->originalId();
|
||||
}
|
||||
} else {
|
||||
Unexpected("Corrupt forwarded information in message.");
|
||||
}
|
||||
config.authorOriginal = original->authorOriginal();
|
||||
config.originalPostAuthor = original->originalPostAuthor();
|
||||
}
|
||||
if (peer->isSelf()) {
|
||||
//
|
||||
|
@ -465,12 +465,12 @@ HistoryItem::HistoryItem(
|
|||
//}
|
||||
}
|
||||
if (flags & MessageFlag::HasPostAuthor) {
|
||||
config.author = postAuthor;
|
||||
config.postAuthor = postAuthor;
|
||||
}
|
||||
if (const auto fwdViaBot = original->viaBot()) {
|
||||
config.viaBotId = peerToUser(fwdViaBot->id);
|
||||
} else if (originalMedia && originalMedia->game()) {
|
||||
if (const auto sender = original->senderOriginal()) {
|
||||
if (const auto sender = original->originalSender()) {
|
||||
if (const auto user = sender->asUser()) {
|
||||
if (user->isBot()) {
|
||||
config.viaBotId = peerToUser(user->id);
|
||||
|
@ -482,8 +482,8 @@ HistoryItem::HistoryItem(
|
|||
if (fwdViewsCount > 0) {
|
||||
config.viewsCount = fwdViewsCount;
|
||||
} else if ((isPost() && !isScheduled())
|
||||
|| (original->senderOriginal()
|
||||
&& original->senderOriginal()->isChannel())) {
|
||||
|| (original->originalSender()
|
||||
&& original->originalSender()->isChannel())) {
|
||||
config.viewsCount = 1;
|
||||
}
|
||||
|
||||
|
@ -1026,7 +1026,7 @@ void HistoryItem::setCommentsItemId(FullMsgId id) {
|
|||
if (id.peer == _history->peer->id) {
|
||||
if (id.msg != this->id) {
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
reply->replyToMsgTop = id.msg;
|
||||
reply->setTopMessageId(id.msg);
|
||||
}
|
||||
}
|
||||
} else if (const auto views = Get<HistoryMessageViews>()) {
|
||||
|
@ -1879,7 +1879,7 @@ void HistoryItem::changeReplyToTopCounter(
|
|||
this,
|
||||
Data::MessageUpdate::Flag::ReplyToTopAdded);
|
||||
}
|
||||
const auto topId = reply->replyToTop();
|
||||
const auto topId = reply->topMessageId();
|
||||
if (!topId) {
|
||||
return;
|
||||
}
|
||||
|
@ -1931,8 +1931,8 @@ void HistoryItem::setRealId(MsgId newId) {
|
|||
_history->owner().requestItemResize(this);
|
||||
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
if (reply->replyToLink()) {
|
||||
reply->setReplyToLinkFrom(this);
|
||||
if (reply->link()) {
|
||||
reply->setLinkFrom(this);
|
||||
}
|
||||
changeReplyToTopCounter(reply, 1);
|
||||
}
|
||||
|
@ -2381,14 +2381,14 @@ not_null<PeerData*> HistoryItem::author() const {
|
|||
return (isPost() && !isSponsored()) ? _history->peer : from();
|
||||
}
|
||||
|
||||
TimeId HistoryItem::dateOriginal() const {
|
||||
TimeId HistoryItem::originalDate() const {
|
||||
if (const auto forwarded = Get<HistoryMessageForwarded>()) {
|
||||
return forwarded->originalDate;
|
||||
}
|
||||
return date();
|
||||
}
|
||||
|
||||
PeerData *HistoryItem::senderOriginal() const {
|
||||
PeerData *HistoryItem::originalSender() const {
|
||||
if (const auto forwarded = Get<HistoryMessageForwarded>()) {
|
||||
return forwarded->originalSender;
|
||||
}
|
||||
|
@ -2416,18 +2416,18 @@ not_null<PeerData*> HistoryItem::fromOriginal() const {
|
|||
return from();
|
||||
}
|
||||
|
||||
QString HistoryItem::authorOriginal() const {
|
||||
QString HistoryItem::originalPostAuthor() const {
|
||||
if (const auto forwarded = Get<HistoryMessageForwarded>()) {
|
||||
return forwarded->originalAuthor;
|
||||
return forwarded->originalPostAuthor;
|
||||
} else if (const auto msgsigned = Get<HistoryMessageSigned>()) {
|
||||
if (!msgsigned->isAnonymousRank) {
|
||||
return msgsigned->author;
|
||||
return msgsigned->postAuthor;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
MsgId HistoryItem::idOriginal() const {
|
||||
MsgId HistoryItem::originalId() const {
|
||||
if (const auto forwarded = Get<HistoryMessageForwarded>()) {
|
||||
return forwarded->originalId;
|
||||
}
|
||||
|
@ -2491,9 +2491,9 @@ void HistoryItem::setForwardsCount(int count) {
|
|||
history()->owner().notifyItemDataChange(this);
|
||||
}
|
||||
|
||||
void HistoryItem::setPostAuthor(const QString &author) {
|
||||
void HistoryItem::setPostAuthor(const QString &postAuthor) {
|
||||
auto msgsigned = Get<HistoryMessageSigned>();
|
||||
if (author.isEmpty()) {
|
||||
if (postAuthor.isEmpty()) {
|
||||
if (!msgsigned) {
|
||||
return;
|
||||
}
|
||||
|
@ -2504,10 +2504,10 @@ void HistoryItem::setPostAuthor(const QString &author) {
|
|||
if (!msgsigned) {
|
||||
AddComponents(HistoryMessageSigned::Bit());
|
||||
msgsigned = Get<HistoryMessageSigned>();
|
||||
} else if (msgsigned->author == author) {
|
||||
} else if (msgsigned->postAuthor == postAuthor) {
|
||||
return;
|
||||
}
|
||||
msgsigned->author = author;
|
||||
msgsigned->postAuthor = postAuthor;
|
||||
msgsigned->isAnonymousRank = !isDiscussionPost()
|
||||
&& this->author()->isMegagroup();
|
||||
history()->owner().requestItemResize(this);
|
||||
|
@ -2643,20 +2643,10 @@ void HistoryItem::setReplyFields(
|
|||
}
|
||||
}
|
||||
} else if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
reply->topicPost = isForumPost;
|
||||
if ((reply->replyToMsgId != replyTo)
|
||||
&& !IsServerMsgId(reply->replyToMsgId)) {
|
||||
reply->replyToMsgId = replyTo;
|
||||
if (!reply->updateData(this)) {
|
||||
RequestDependentMessageItem(
|
||||
this,
|
||||
reply->replyToPeerId,
|
||||
reply->replyToMsgId);
|
||||
}
|
||||
}
|
||||
if ((reply->replyToMsgTop != replyToTop)
|
||||
&& !IsServerMsgId(reply->replyToMsgTop)) {
|
||||
reply->replyToMsgTop = replyToTop;
|
||||
const auto increment = (reply->topMessageId() != replyToTop)
|
||||
&& !IsServerMsgId(reply->topMessageId());
|
||||
reply->updateFields(this, replyTo, replyToTop, isForumPost);
|
||||
if (increment) {
|
||||
changeReplyToTopCounter(reply, 1);
|
||||
}
|
||||
}
|
||||
|
@ -2819,14 +2809,22 @@ bool HistoryItem::unread(not_null<Data::Thread*> thread) const {
|
|||
|
||||
MsgId HistoryItem::replyToId() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
return reply->replyToId();
|
||||
return reply->messageId();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
FullMsgId HistoryItem::replyToFullId() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
const auto peer = reply->externalPeerId();
|
||||
return { peer ? peer : history()->peer->id, reply->messageId() };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
MsgId HistoryItem::replyToTop() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
return reply->replyToTop();
|
||||
return reply->topMessageId();
|
||||
} else if (const auto data = GetServiceDependentData()) {
|
||||
return data->topId;
|
||||
}
|
||||
|
@ -2835,8 +2833,8 @@ MsgId HistoryItem::replyToTop() const {
|
|||
|
||||
MsgId HistoryItem::topicRootId() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()
|
||||
; reply && reply->topicPost) {
|
||||
return reply->replyToTop();
|
||||
; reply && reply->topicPost()) {
|
||||
return reply->topMessageId();
|
||||
} else if (const auto data = GetServiceDependentData()
|
||||
; data && data->topicPost && data->topId) {
|
||||
return data->topId;
|
||||
|
@ -2850,11 +2848,11 @@ MsgId HistoryItem::topicRootId() const {
|
|||
|
||||
FullStoryId HistoryItem::replyToStory() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
if (reply->replyToStoryId) {
|
||||
const auto peerId = reply->replyToPeerId
|
||||
? reply->replyToPeerId
|
||||
if (reply->storyId()) {
|
||||
const auto peerId = reply->externalPeerId()
|
||||
? reply->externalPeerId()
|
||||
: _history->peer->id;
|
||||
return { .peer = peerId, .story = reply->replyToStoryId };
|
||||
return { .peer = peerId, .story = reply->storyId() };
|
||||
}
|
||||
}
|
||||
return {};
|
||||
|
@ -2862,9 +2860,9 @@ FullStoryId HistoryItem::replyToStory() const {
|
|||
|
||||
FullReplyTo HistoryItem::replyTo() const {
|
||||
return {
|
||||
.msgId = replyToId(),
|
||||
.topicRootId = topicRootId(),
|
||||
.messageId = replyToFullId(),
|
||||
.storyId = replyToStory(),
|
||||
.topicRootId = topicRootId(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -3049,7 +3047,10 @@ const std::vector<ClickHandlerPtr> &HistoryItem::customTextLinks() const {
|
|||
|
||||
void HistoryItem::createComponents(CreateConfig &&config) {
|
||||
uint64 mask = 0;
|
||||
if (config.replyTo || config.replyToStory) {
|
||||
if (config.reply.messageId
|
||||
|| config.reply.externalSenderId
|
||||
|| !config.reply.externalSenderName.isEmpty()
|
||||
|| config.reply.storyId) {
|
||||
mask |= HistoryMessageReply::Bit();
|
||||
}
|
||||
if (config.viaBotId) {
|
||||
|
@ -3058,18 +3059,18 @@ void HistoryItem::createComponents(CreateConfig &&config) {
|
|||
if (config.viewsCount >= 0 || !config.replies.isNull) {
|
||||
mask |= HistoryMessageViews::Bit();
|
||||
}
|
||||
if (!config.author.isEmpty()) {
|
||||
if (!config.postAuthor.isEmpty()) {
|
||||
mask |= HistoryMessageSigned::Bit();
|
||||
} else if (_history->peer->isMegagroup() // Discussion posts signatures.
|
||||
&& config.savedFromPeer
|
||||
&& !config.authorOriginal.isEmpty()) {
|
||||
&& !config.originalPostAuthor.isEmpty()) {
|
||||
const auto savedFrom = _history->owner().peerLoaded(
|
||||
config.savedFromPeer);
|
||||
if (savedFrom && savedFrom->isChannel()) {
|
||||
mask |= HistoryMessageSigned::Bit();
|
||||
}
|
||||
} else if ((_history->peer->isSelf() || _history->peer->isRepliesChat())
|
||||
&& !config.authorOriginal.isEmpty()) {
|
||||
&& !config.originalPostAuthor.isEmpty()) {
|
||||
mask |= HistoryMessageSigned::Bit();
|
||||
}
|
||||
if (config.editDate != TimeId(0)) {
|
||||
|
@ -3087,23 +3088,18 @@ void HistoryItem::createComponents(CreateConfig &&config) {
|
|||
UpdateComponents(mask);
|
||||
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
reply->replyToPeerId = config.replyToPeer;
|
||||
reply->replyToMsgId = config.replyTo;
|
||||
reply->replyToMsgTop = isScheduled() ? 0 : config.replyToTop;
|
||||
reply->replyToStoryId = config.replyToStory;
|
||||
reply->storyReply = (config.replyToStory != 0);
|
||||
reply->topicPost = config.replyIsTopicPost;
|
||||
reply->set(config.reply);
|
||||
if (!reply->updateData(this)) {
|
||||
if (reply->replyToMsgId) {
|
||||
if (const auto messageId = reply->messageId()) {
|
||||
RequestDependentMessageItem(
|
||||
this,
|
||||
reply->replyToPeerId,
|
||||
reply->replyToMsgId);
|
||||
} else if (reply->replyToStoryId) {
|
||||
reply->externalPeerId(),
|
||||
reply->messageId());
|
||||
} else if (reply->storyId()) {
|
||||
RequestDependentMessageStory(
|
||||
this,
|
||||
reply->replyToPeerId,
|
||||
reply->replyToStoryId);
|
||||
reply->externalPeerId(),
|
||||
reply->storyId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3129,9 +3125,9 @@ void HistoryItem::createComponents(CreateConfig &&config) {
|
|||
edited->date = config.editDate;
|
||||
}
|
||||
if (const auto msgsigned = Get<HistoryMessageSigned>()) {
|
||||
msgsigned->author = config.author.isEmpty()
|
||||
? config.authorOriginal
|
||||
: config.author;
|
||||
msgsigned->postAuthor = config.postAuthor.isEmpty()
|
||||
? config.originalPostAuthor
|
||||
: config.postAuthor;
|
||||
msgsigned->isAnonymousRank = !isDiscussionPost()
|
||||
&& author()->isMegagroup();
|
||||
}
|
||||
|
@ -3167,9 +3163,9 @@ void HistoryItem::setupForwardedComponent(const CreateConfig &config) {
|
|||
return;
|
||||
}
|
||||
forwarded->originalDate = config.originalDate;
|
||||
const auto originalSender = config.senderOriginal
|
||||
? config.senderOriginal
|
||||
: !config.senderNameOriginal.isEmpty()
|
||||
const auto originalSender = config.originalSenderId
|
||||
? config.originalSenderId
|
||||
: !config.originalSenderName.isEmpty()
|
||||
? PeerId()
|
||||
: from()->id;
|
||||
forwarded->originalSender = originalSender
|
||||
|
@ -3177,11 +3173,11 @@ void HistoryItem::setupForwardedComponent(const CreateConfig &config) {
|
|||
: nullptr;
|
||||
if (!forwarded->originalSender) {
|
||||
forwarded->hiddenSenderInfo = std::make_unique<HiddenSenderInfo>(
|
||||
config.senderNameOriginal,
|
||||
config.originalSenderName,
|
||||
config.imported);
|
||||
}
|
||||
forwarded->originalId = config.originalId;
|
||||
forwarded->originalAuthor = config.authorOriginal;
|
||||
forwarded->originalPostAuthor = config.originalPostAuthor;
|
||||
forwarded->psaType = config.forwardPsaType;
|
||||
forwarded->savedFromPeer = _history->owner().peerLoaded(
|
||||
config.savedFromPeer);
|
||||
|
@ -3233,7 +3229,7 @@ TextWithEntities HistoryItem::withLocalEntities(
|
|||
: nullptr;
|
||||
if (document) {
|
||||
if (const auto duration = DurationForTimestampLinks(document)) {
|
||||
const auto context = reply->replyToMsg->fullId();
|
||||
const auto context = reply->resolvedMessage->fullId();
|
||||
return AddTimestampLinks(
|
||||
textWithEntities,
|
||||
duration,
|
||||
|
@ -3241,7 +3237,7 @@ TextWithEntities HistoryItem::withLocalEntities(
|
|||
}
|
||||
} else if (webpage) {
|
||||
if (const auto duration = DurationForTimestampLinks(webpage)) {
|
||||
const auto context = reply->replyToMsg->fullId();
|
||||
const auto context = reply->resolvedMessage->fullId();
|
||||
return AddTimestampLinks(
|
||||
textWithEntities,
|
||||
duration,
|
||||
|
@ -3290,19 +3286,28 @@ void HistoryItem::createComponentsHelper(
|
|||
auto config = CreateConfig();
|
||||
config.viaBotId = viaBotId;
|
||||
if (flags & MessageFlag::HasReplyInfo) {
|
||||
config.replyTo = replyTo.msgId;
|
||||
config.replyToStory = replyTo.storyId.story;
|
||||
config.replyToPeer = replyTo.storyId ? replyTo.storyId.peer : 0;
|
||||
const auto to = LookupReplyTo(_history, replyTo.msgId);
|
||||
const auto replyToTop = LookupReplyToTop(to);
|
||||
config.replyToTop = replyToTop ? replyToTop : replyTo.msgId;
|
||||
config.reply.messageId = replyTo.messageId.msg;
|
||||
config.reply.storyId = replyTo.storyId.story;
|
||||
config.reply.externalPeerId = replyTo.storyId
|
||||
? replyTo.storyId.peer
|
||||
: (replyTo.messageId && replyTo.messageId.peer
|
||||
!= history()->peer->id)
|
||||
? replyTo.messageId.peer
|
||||
: PeerId();
|
||||
const auto to = LookupReplyTo(_history, replyTo.messageId);
|
||||
const auto replyToTop = LookupReplyToTop(_history, to);
|
||||
config.reply.topMessageId = replyToTop
|
||||
? replyToTop
|
||||
: (replyTo.messageId.peer == history()->peer->id)
|
||||
? replyTo.messageId.msg
|
||||
: MsgId();
|
||||
const auto forum = _history->asForum();
|
||||
config.replyIsTopicPost = LookupReplyIsTopicPost(to)
|
||||
config.reply.topicPost = LookupReplyIsTopicPost(to)
|
||||
|| (to && to->Has<HistoryServiceTopicInfo>())
|
||||
|| (forum && forum->creating(config.replyToTop));
|
||||
|| (forum && forum->creating(config.reply.topMessageId));
|
||||
}
|
||||
config.markup = std::move(markup);
|
||||
if (flags & MessageFlag::HasPostAuthor) config.author = postAuthor;
|
||||
if (flags & MessageFlag::HasPostAuthor) config.postAuthor = postAuthor;
|
||||
if (flags & MessageFlag::HasViews) config.viewsCount = 1;
|
||||
|
||||
createComponents(std::move(config));
|
||||
|
@ -3392,26 +3397,7 @@ void HistoryItem::createComponents(const MTPDmessage &data) {
|
|||
});
|
||||
}
|
||||
if (const auto reply = data.vreply_to()) {
|
||||
reply->match([&](const MTPDmessageReplyHeader &data) {
|
||||
// #TODO replies
|
||||
if (const auto id = data.vreply_to_msg_id().value_or_empty()) {
|
||||
if (const auto peer = data.vreply_to_peer_id()) {
|
||||
config.replyToPeer = peerFromMTP(*peer);
|
||||
if (config.replyToPeer == _history->peer->id) {
|
||||
config.replyToPeer = 0;
|
||||
}
|
||||
}
|
||||
const auto owner = &_history->owner();
|
||||
config.replyTo = data.is_reply_to_scheduled()
|
||||
? owner->scheduledMessages().localMessageId(id)
|
||||
: id;
|
||||
config.replyToTop = data.vreply_to_top_id().value_or(id);
|
||||
config.replyIsTopicPost = data.is_forum_topic();
|
||||
}
|
||||
}, [&](const MTPDmessageReplyStoryHeader &data) {
|
||||
config.replyToPeer = peerFromUser(data.vuser_id());
|
||||
config.replyToStory = data.vstory_id().v;
|
||||
});
|
||||
config.reply = ReplyFieldsFromMTP(history(), *reply);
|
||||
}
|
||||
config.viaBotId = data.vvia_bot_id().value_or_empty();
|
||||
config.viewsCount = data.vviews().value_or(-1);
|
||||
|
@ -3421,7 +3407,7 @@ void HistoryItem::createComponents(const MTPDmessage &data) {
|
|||
: HistoryMessageRepliesData(data.vreplies());
|
||||
config.markup = HistoryMessageMarkupData(data.vreply_markup());
|
||||
config.editDate = data.vedit_date().value_or_empty();
|
||||
config.author = qs(data.vpost_author().value_or_empty());
|
||||
config.postAuthor = qs(data.vpost_author().value_or_empty());
|
||||
createComponents(std::move(config));
|
||||
}
|
||||
|
||||
|
|
|
@ -465,6 +465,7 @@ public:
|
|||
void setText(const TextWithEntities &textWithEntities);
|
||||
|
||||
[[nodiscard]] MsgId replyToId() const;
|
||||
[[nodiscard]] FullMsgId replyToFullId() const;
|
||||
[[nodiscard]] MsgId replyToTop() const;
|
||||
[[nodiscard]] MsgId topicRootId() const;
|
||||
[[nodiscard]] FullStoryId replyToStory() const;
|
||||
|
@ -473,12 +474,12 @@ public:
|
|||
|
||||
[[nodiscard]] not_null<PeerData*> author() const;
|
||||
|
||||
[[nodiscard]] TimeId dateOriginal() const;
|
||||
[[nodiscard]] PeerData *senderOriginal() const;
|
||||
[[nodiscard]] TimeId originalDate() const;
|
||||
[[nodiscard]] PeerData *originalSender() const;
|
||||
[[nodiscard]] const HiddenSenderInfo *hiddenSenderInfo() const;
|
||||
[[nodiscard]] not_null<PeerData*> fromOriginal() const;
|
||||
[[nodiscard]] QString authorOriginal() const;
|
||||
[[nodiscard]] MsgId idOriginal() const;
|
||||
[[nodiscard]] QString originalPostAuthor() const;
|
||||
[[nodiscard]] MsgId originalId() const;
|
||||
|
||||
[[nodiscard]] bool isEmpty() const;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "history/history_item_components.h"
|
||||
|
||||
#include "api/api_text_entities.h"
|
||||
#include "base/qt/qt_key_modifiers.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
|
@ -38,6 +39,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_document.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "data/data_file_click_handler.h"
|
||||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_stories.h"
|
||||
#include "main/main_session.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
@ -64,7 +67,7 @@ void HistoryMessageVia::create(
|
|||
lt_inline_bot,
|
||||
'@' + bot->username()));
|
||||
link = std::make_shared<LambdaClickHandler>([bot = this->bot](
|
||||
ClickContext context) {
|
||||
ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto controller = my.sessionWindow.get()) {
|
||||
if (base::IsCtrlPressed()) {
|
||||
|
@ -183,13 +186,13 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
|
|||
? originalSender->name()
|
||||
: hiddenSenderInfo->name)
|
||||
};
|
||||
if (!originalAuthor.isEmpty()) {
|
||||
if (!originalPostAuthor.isEmpty()) {
|
||||
phrase = tr::lng_forwarded_signed(
|
||||
tr::now,
|
||||
lt_channel,
|
||||
name,
|
||||
lt_user,
|
||||
{ .text = originalAuthor },
|
||||
{ .text = originalPostAuthor },
|
||||
Ui::Text::WithEntities);
|
||||
} else {
|
||||
phrase = name;
|
||||
|
@ -261,6 +264,51 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
|
|||
}
|
||||
}
|
||||
|
||||
ReplyFields ReplyFieldsFromMTP(
|
||||
not_null<History*> history,
|
||||
const MTPMessageReplyHeader &reply) {
|
||||
return reply.match([&](const MTPDmessageReplyHeader &data) {
|
||||
auto result = ReplyFields();
|
||||
if (const auto peer = data.vreply_to_peer_id()) {
|
||||
result.externalPeerId = peerFromMTP(*peer);
|
||||
if (result.externalPeerId == history->peer->id) {
|
||||
result.externalPeerId = 0;
|
||||
}
|
||||
}
|
||||
const auto owner = &history->owner();
|
||||
if (const auto id = data.vreply_to_msg_id().value_or_empty()) {
|
||||
result.messageId = data.is_reply_to_scheduled()
|
||||
? owner->scheduledMessages().localMessageId(id)
|
||||
: id;
|
||||
result.topMessageId
|
||||
= data.vreply_to_top_id().value_or(id);
|
||||
result.topicPost = data.is_forum_topic();
|
||||
}
|
||||
if (const auto header = data.vreply_header()) {
|
||||
const auto &data = header->data();
|
||||
result.externalPostAuthor
|
||||
= qs(data.vpost_author().value_or_empty());
|
||||
result.externalSenderId = data.vfrom_id()
|
||||
? peerFromMTP(*data.vfrom_id())
|
||||
: PeerId();
|
||||
result.externalSenderName
|
||||
= qs(data.vfrom_name().value_or_empty());
|
||||
}
|
||||
result.quote = TextWithEntities{
|
||||
qs(data.vquote_text().value_or_empty()),
|
||||
Api::EntitiesFromMTP(
|
||||
&owner->session(),
|
||||
data.vquote_entities().value_or_empty()),
|
||||
};
|
||||
return result;
|
||||
}, [&](const MTPDmessageReplyStoryHeader &data) {
|
||||
return ReplyFields{
|
||||
.externalPeerId = peerFromUser(data.vuser_id()),
|
||||
.storyId = data.vstory_id().v,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
HistoryMessageReply::HistoryMessageReply() = default;
|
||||
|
||||
HistoryMessageReply &HistoryMessageReply::operator=(
|
||||
|
@ -268,8 +316,8 @@ HistoryMessageReply &HistoryMessageReply::operator=(
|
|||
|
||||
HistoryMessageReply::~HistoryMessageReply() {
|
||||
// clearData() should be called by holder.
|
||||
Expects(replyToMsg.empty());
|
||||
Expects(replyToVia == nullptr);
|
||||
Expects(resolvedMessage.empty());
|
||||
Expects(originalVia == nullptr);
|
||||
}
|
||||
|
||||
bool HistoryMessageReply::updateData(
|
||||
|
@ -277,166 +325,228 @@ bool HistoryMessageReply::updateData(
|
|||
bool force) {
|
||||
const auto guard = gsl::finally([&] { refreshReplyToMedia(); });
|
||||
if (!force) {
|
||||
if ((replyToMsg || !replyToMsgId)
|
||||
&& (replyToStory || !replyToStoryId)) {
|
||||
if (resolvedMessage || resolvedStory || _deleted) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const auto peerId = replyToPeerId
|
||||
? replyToPeerId
|
||||
const auto peerId = _fields.externalPeerId
|
||||
? _fields.externalPeerId
|
||||
: holder->history()->peer->id;
|
||||
if (!replyToMsg && replyToMsgId) {
|
||||
replyToMsg = holder->history()->owner().message(
|
||||
if (!resolvedMessage && _fields.messageId) {
|
||||
resolvedMessage = holder->history()->owner().message(
|
||||
peerId,
|
||||
replyToMsgId);
|
||||
if (replyToMsg) {
|
||||
if (replyToMsg->isEmpty()) {
|
||||
_fields.messageId);
|
||||
if (resolvedMessage) {
|
||||
if (resolvedMessage->isEmpty()) {
|
||||
// Really it is deleted.
|
||||
replyToMsg = nullptr;
|
||||
resolvedMessage = nullptr;
|
||||
force = true;
|
||||
} else {
|
||||
holder->history()->owner().registerDependentMessage(
|
||||
holder,
|
||||
replyToMsg.get());
|
||||
resolvedMessage.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!replyToStory && replyToStoryId) {
|
||||
if (!resolvedStory && _fields.storyId) {
|
||||
const auto maybe = holder->history()->owner().stories().lookup({
|
||||
peerId,
|
||||
replyToStoryId,
|
||||
_fields.storyId,
|
||||
});
|
||||
if (maybe) {
|
||||
replyToStory = *maybe;
|
||||
resolvedStory = *maybe;
|
||||
holder->history()->owner().stories().registerDependentMessage(
|
||||
holder,
|
||||
replyToStory.get());
|
||||
resolvedStory.get());
|
||||
} else if (maybe.error() == Data::NoStory::Deleted) {
|
||||
force = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (replyToMsg || replyToStory) {
|
||||
const auto external = _fields.externalSenderId
|
||||
|| !_fields.externalSenderName.isEmpty();
|
||||
if (resolvedMessage || resolvedStory || (external && force)) {
|
||||
const auto repaint = [=] { holder->customEmojiRepaint(); };
|
||||
const auto context = Core::MarkedTextContext{
|
||||
.session = &holder->history()->session(),
|
||||
.customEmojiRepaint = repaint,
|
||||
};
|
||||
replyToText.setMarkedText(
|
||||
const auto text = !_fields.quote.empty()
|
||||
? _fields.quote
|
||||
: resolvedMessage
|
||||
? resolvedMessage->inReplyText()
|
||||
: resolvedStory
|
||||
? resolvedStory->inReplyText()
|
||||
: TextWithEntities{ u"..."_q };
|
||||
_text.setMarkedText(
|
||||
st::defaultTextStyle,
|
||||
(replyToMsg
|
||||
? replyToMsg->inReplyText()
|
||||
: replyToStory->inReplyText()),
|
||||
text,
|
||||
Ui::DialogTextOptions(),
|
||||
context);
|
||||
|
||||
updateName(holder);
|
||||
|
||||
setReplyToLinkFrom(holder);
|
||||
if (replyToMsg && !replyToMsg->Has<HistoryMessageForwarded>()) {
|
||||
if (auto bot = replyToMsg->viaBot()) {
|
||||
replyToVia = std::make_unique<HistoryMessageVia>();
|
||||
replyToVia->create(
|
||||
setLinkFrom(holder);
|
||||
if (resolvedMessage
|
||||
&& !resolvedMessage->Has<HistoryMessageForwarded>()) {
|
||||
if (const auto bot = resolvedMessage->viaBot()) {
|
||||
originalVia = std::make_unique<HistoryMessageVia>();
|
||||
originalVia->create(
|
||||
&holder->history()->owner(),
|
||||
peerToUser(bot->id));
|
||||
}
|
||||
}
|
||||
|
||||
if (replyToMsg) {
|
||||
const auto peer = replyToMsg->history()->peer;
|
||||
replyToColorKey = (!holder->out()
|
||||
if (resolvedMessage) {
|
||||
const auto peer = resolvedMessage->history()->peer;
|
||||
_colorKey = (!holder->out()
|
||||
&& (peer->isMegagroup() || peer->isChat())
|
||||
&& replyToMsg->from()->isUser())
|
||||
? replyToMsg->from()->id
|
||||
: PeerId(0);
|
||||
&& resolvedMessage->from()->isUser())
|
||||
? resolvedMessage->from()->id
|
||||
: PeerId();
|
||||
} else {
|
||||
replyToColorKey = PeerId(0);
|
||||
resolvedMessage = 0;
|
||||
}
|
||||
|
||||
const auto media = replyToMsg ? replyToMsg->media() : nullptr;
|
||||
const auto media = resolvedMessage
|
||||
? resolvedMessage->media()
|
||||
: nullptr;
|
||||
if (!media || !media->hasReplyPreview() || !media->hasSpoiler()) {
|
||||
spoiler = nullptr;
|
||||
} else if (!spoiler) {
|
||||
spoiler = std::make_unique<Ui::SpoilerAnimation>(repaint);
|
||||
}
|
||||
} else if (force) {
|
||||
replyToMsgId = 0;
|
||||
replyToStoryId = 0;
|
||||
replyToColorKey = PeerId(0);
|
||||
if (_fields.messageId || _fields.storyId) {
|
||||
_deleted = true;
|
||||
}
|
||||
_colorKey = 0;
|
||||
spoiler = nullptr;
|
||||
}
|
||||
if (force) {
|
||||
holder->history()->owner().requestItemResize(holder);
|
||||
}
|
||||
return (replyToMsg || !replyToMsgId)
|
||||
&& (replyToStory || !replyToStoryId);
|
||||
return resolvedMessage
|
||||
|| resolvedStory
|
||||
|| (external && !_fields.messageId)
|
||||
|| _deleted;
|
||||
}
|
||||
|
||||
void HistoryMessageReply::setReplyToLinkFrom(
|
||||
void HistoryMessageReply::set(ReplyFields fields) {
|
||||
_fields = std::move(fields);
|
||||
}
|
||||
|
||||
void HistoryMessageReply::updateFields(
|
||||
not_null<HistoryItem*> holder,
|
||||
MsgId messageId,
|
||||
MsgId topMessageId,
|
||||
bool topicPost) {
|
||||
_fields.topicPost = topicPost;
|
||||
if ((_fields.messageId != messageId)
|
||||
&& !IsServerMsgId(_fields.messageId)) {
|
||||
_fields.messageId = messageId;
|
||||
if (!updateData(holder)) {
|
||||
RequestDependentMessageItem(
|
||||
holder,
|
||||
_fields.externalPeerId,
|
||||
_fields.messageId);
|
||||
}
|
||||
}
|
||||
if ((_fields.topMessageId != topMessageId)
|
||||
&& !IsServerMsgId(_fields.topMessageId)) {
|
||||
_fields.topMessageId = topMessageId;
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryMessageReply::setLinkFrom(
|
||||
not_null<HistoryItem*> holder) {
|
||||
replyToLnk = replyToMsg
|
||||
? JumpToMessageClickHandler(replyToMsg.get(), holder->fullId())
|
||||
: replyToStory
|
||||
? JumpToStoryClickHandler(replyToStory.get())
|
||||
const auto externalPeerId = _fields.externalSenderId;
|
||||
const auto external = externalPeerId
|
||||
|| !_fields.externalSenderName.isEmpty();
|
||||
const auto externalLink = [=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
if (const auto controller = my.sessionWindow.get()) {
|
||||
if (externalPeerId) {
|
||||
controller->showPeerInfo(
|
||||
controller->session().data().peer(externalPeerId));
|
||||
} else {
|
||||
controller->showToast(u"External reply"_q);
|
||||
}
|
||||
}
|
||||
};
|
||||
_link = resolvedMessage
|
||||
? JumpToMessageClickHandler(resolvedMessage.get(), holder->fullId())
|
||||
: resolvedStory
|
||||
? JumpToStoryClickHandler(resolvedStory.get())
|
||||
: (external && !_fields.messageId)
|
||||
? std::make_shared<LambdaClickHandler>(externalLink)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void HistoryMessageReply::setTopMessageId(MsgId topMessageId) {
|
||||
_fields.topMessageId = topMessageId;
|
||||
}
|
||||
|
||||
void HistoryMessageReply::clearData(not_null<HistoryItem*> holder) {
|
||||
replyToVia = nullptr;
|
||||
if (replyToMsg) {
|
||||
originalVia = nullptr;
|
||||
if (resolvedMessage) {
|
||||
holder->history()->owner().unregisterDependentMessage(
|
||||
holder,
|
||||
replyToMsg.get());
|
||||
replyToMsg = nullptr;
|
||||
resolvedMessage.get());
|
||||
resolvedMessage = nullptr;
|
||||
}
|
||||
if (replyToStory) {
|
||||
if (resolvedStory) {
|
||||
holder->history()->owner().stories().unregisterDependentMessage(
|
||||
holder,
|
||||
replyToStory.get());
|
||||
replyToStory = nullptr;
|
||||
resolvedStory.get());
|
||||
resolvedStory = nullptr;
|
||||
}
|
||||
replyToMsgId = 0;
|
||||
replyToStoryId = 0;
|
||||
_deleted = true;
|
||||
refreshReplyToMedia();
|
||||
}
|
||||
|
||||
PeerData *HistoryMessageReply::replyToFrom(
|
||||
not_null<HistoryItem*> holder) const {
|
||||
if (!replyToMsg) {
|
||||
return nullptr;
|
||||
PeerData *HistoryMessageReply::sender(not_null<HistoryItem*> holder) const {
|
||||
if (resolvedStory) {
|
||||
return resolvedStory->peer();
|
||||
} else if (!resolvedMessage) {
|
||||
if (!_externalSender && _fields.externalSenderId) {
|
||||
_externalSender = holder->history()->owner().peer(
|
||||
_fields.externalSenderId);
|
||||
}
|
||||
return _externalSender;
|
||||
} else if (holder->Has<HistoryMessageForwarded>()) {
|
||||
if (const auto fwd = replyToMsg->Get<HistoryMessageForwarded>()) {
|
||||
return fwd->originalSender;
|
||||
// Forward of a reply. Show reply-to original sender.
|
||||
const auto forwarded
|
||||
= resolvedMessage->Get<HistoryMessageForwarded>();
|
||||
if (forwarded) {
|
||||
return forwarded->originalSender;
|
||||
}
|
||||
}
|
||||
if (const auto from = replyToMsg->displayFrom()) {
|
||||
if (const auto from = resolvedMessage->displayFrom()) {
|
||||
return from;
|
||||
}
|
||||
return replyToMsg->author().get();
|
||||
return resolvedMessage->author().get();
|
||||
}
|
||||
|
||||
QString HistoryMessageReply::replyToFromName(
|
||||
QString HistoryMessageReply::senderName(
|
||||
not_null<HistoryItem*> holder) const {
|
||||
if (replyToStory) {
|
||||
return replyToFromName(replyToStory->peer());
|
||||
} else if (!replyToMsg) {
|
||||
return QString();
|
||||
if (const auto peer = sender(holder)) {
|
||||
return senderName(peer);
|
||||
} else if (!resolvedMessage) {
|
||||
return _fields.externalSenderName;
|
||||
} else if (holder->Has<HistoryMessageForwarded>()) {
|
||||
if (const auto fwd = replyToMsg->Get<HistoryMessageForwarded>()) {
|
||||
return fwd->originalSender
|
||||
? replyToFromName(fwd->originalSender)
|
||||
: fwd->hiddenSenderInfo->name;
|
||||
// Forward of a reply. Show reply-to original sender.
|
||||
const auto forwarded
|
||||
= resolvedMessage->Get<HistoryMessageForwarded>();
|
||||
if (forwarded) {
|
||||
Assert(forwarded->hiddenSenderInfo != nullptr);
|
||||
return forwarded->hiddenSenderInfo->name;
|
||||
}
|
||||
}
|
||||
if (const auto from = replyToMsg->displayFrom()) {
|
||||
return replyToFromName(from);
|
||||
}
|
||||
return replyToFromName(replyToMsg->author());
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString HistoryMessageReply::replyToFromName(
|
||||
not_null<PeerData*> peer) const {
|
||||
if (const auto user = replyToVia ? peer->asUser() : nullptr) {
|
||||
QString HistoryMessageReply::senderName(not_null<PeerData*> peer) const {
|
||||
if (const auto user = originalVia ? peer->asUser() : nullptr) {
|
||||
return user->firstName;
|
||||
}
|
||||
return peer->name();
|
||||
|
@ -444,9 +554,9 @@ QString HistoryMessageReply::replyToFromName(
|
|||
|
||||
bool HistoryMessageReply::isNameUpdated(
|
||||
not_null<HistoryItem*> holder) const {
|
||||
if (const auto from = replyToFrom(holder)) {
|
||||
if (replyToVersion < from->nameVersion()) {
|
||||
updateName(holder);
|
||||
if (const auto from = sender(holder)) {
|
||||
if (_nameVersion < from->nameVersion()) {
|
||||
updateName(holder, from);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -454,55 +564,73 @@ bool HistoryMessageReply::isNameUpdated(
|
|||
}
|
||||
|
||||
void HistoryMessageReply::updateName(
|
||||
not_null<HistoryItem*> holder) const {
|
||||
if (const auto name = replyToFromName(holder); !name.isEmpty()) {
|
||||
replyToName.setText(st::fwdTextStyle, name, Ui::NameTextOptions());
|
||||
if (const auto from = replyToFrom(holder)) {
|
||||
replyToVersion = from->nameVersion();
|
||||
} else if (replyToMsg) {
|
||||
replyToVersion = replyToMsg->author()->nameVersion();
|
||||
} else {
|
||||
replyToVersion = replyToStory->peer()->nameVersion();
|
||||
not_null<HistoryItem*> holder,
|
||||
std::optional<PeerData*> resolvedSender) const {
|
||||
const auto peer = resolvedSender.value_or(sender(holder));
|
||||
const auto name = peer ? senderName(peer) : senderName(holder);
|
||||
if (!name.isEmpty()) {
|
||||
_name.setText(st::fwdTextStyle, name, Ui::NameTextOptions());
|
||||
if (peer) {
|
||||
_nameVersion = peer->nameVersion();
|
||||
}
|
||||
bool hasPreview = (replyToStory && replyToStory->hasReplyPreview())
|
||||
|| (replyToMsg
|
||||
&& replyToMsg->media()
|
||||
&& replyToMsg->media()->hasReplyPreview());
|
||||
int32 previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0;
|
||||
int32 w = replyToName.maxWidth();
|
||||
if (replyToVia) {
|
||||
w += st::msgServiceFont->spacew + replyToVia->maxWidth;
|
||||
bool hasPreview = (resolvedStory
|
||||
&& resolvedStory->hasReplyPreview())
|
||||
|| (resolvedMessage
|
||||
&& resolvedMessage->media()
|
||||
&& resolvedMessage->media()->hasReplyPreview());
|
||||
int32 previewSkip = hasPreview
|
||||
? (st::msgReplyBarSize.height()
|
||||
+ st::msgReplyBarSkip
|
||||
- st::msgReplyBarSize.width()
|
||||
- st::msgReplyBarPos.x())
|
||||
: 0;
|
||||
int32 w = _name.maxWidth();
|
||||
if (originalVia) {
|
||||
w += st::msgServiceFont->spacew + originalVia->maxWidth;
|
||||
}
|
||||
|
||||
maxReplyWidth = previewSkip
|
||||
_maxWidth = previewSkip
|
||||
+ std::max(
|
||||
w,
|
||||
std::min(replyToText.maxWidth(), st::maxSignatureSize))
|
||||
+ (storyReply
|
||||
std::min(_text.maxWidth(), st::maxSignatureSize))
|
||||
+ (_fields.storyId
|
||||
? (st::dialogsMiniReplyStory.skipText
|
||||
+ st::dialogsMiniReplyStory.icon.icon.width())
|
||||
: 0);
|
||||
} else {
|
||||
maxReplyWidth = st::msgDateFont->width(statePhrase());
|
||||
_maxWidth = st::msgDateFont->width(statePhrase());
|
||||
}
|
||||
maxReplyWidth = st::msgReplyPadding.left() + st::msgReplyBarSkip + maxReplyWidth + st::msgReplyPadding.right();
|
||||
_maxWidth = st::msgReplyPadding.left()
|
||||
+ st::msgReplyBarSkip
|
||||
+ _maxWidth
|
||||
+ st::msgReplyPadding.right();
|
||||
}
|
||||
|
||||
void HistoryMessageReply::resize(int width) const {
|
||||
if (replyToVia) {
|
||||
bool hasPreview = (replyToStory && replyToStory->hasReplyPreview())
|
||||
|| (replyToMsg
|
||||
&& replyToMsg->media()
|
||||
&& replyToMsg->media()->hasReplyPreview());
|
||||
int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0;
|
||||
replyToVia->resize(width - st::msgReplyBarSkip - previewSkip - replyToName.maxWidth() - st::msgServiceFont->spacew);
|
||||
if (originalVia) {
|
||||
bool hasPreview = (resolvedStory
|
||||
&& resolvedStory->hasReplyPreview())
|
||||
|| (resolvedMessage
|
||||
&& resolvedMessage->media()
|
||||
&& resolvedMessage->media()->hasReplyPreview());
|
||||
int previewSkip = hasPreview
|
||||
? (st::msgReplyBarSize.height()
|
||||
+ st::msgReplyBarSkip
|
||||
- st::msgReplyBarSize.width()
|
||||
- st::msgReplyBarPos.x())
|
||||
: 0;
|
||||
originalVia->resize(width
|
||||
- st::msgReplyBarSkip
|
||||
- previewSkip
|
||||
- _name.maxWidth()
|
||||
- st::msgServiceFont->spacew);
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryMessageReply::itemRemoved(
|
||||
not_null<HistoryItem*> holder,
|
||||
not_null<HistoryItem*> removed) {
|
||||
if (replyToMsg.get() == removed) {
|
||||
if (resolvedMessage.get() == removed) {
|
||||
clearData(holder);
|
||||
holder->history()->owner().requestItemResize(holder);
|
||||
}
|
||||
|
@ -511,7 +639,7 @@ void HistoryMessageReply::itemRemoved(
|
|||
void HistoryMessageReply::storyRemoved(
|
||||
not_null<HistoryItem*> holder,
|
||||
not_null<Data::Story*> removed) {
|
||||
if (replyToStory.get() == removed) {
|
||||
if (resolvedStory.get() == removed) {
|
||||
clearData(holder);
|
||||
holder->history()->owner().requestItemResize(holder);
|
||||
}
|
||||
|
@ -533,8 +661,8 @@ void HistoryMessageReply::paint(
|
|||
const auto outerWidth = w + 2 * x;
|
||||
const auto &bar = !inBubble
|
||||
? st->msgImgReplyBarColor()
|
||||
: replyToColorKey
|
||||
? HistoryView::FromNameFg(context, replyToColorKey)
|
||||
: _colorKey
|
||||
? HistoryView::FromNameFg(context, _colorKey)
|
||||
: stm->msgReplyBarColor;
|
||||
const auto rbar = style::rtlrect(
|
||||
x + st::msgReplyBarPos.x(),
|
||||
|
@ -565,9 +693,10 @@ void HistoryMessageReply::paint(
|
|||
const auto pausedSpoiler = context.paused
|
||||
|| On(PowerSaving::kChatSpoiler);
|
||||
if (w > st::msgReplyBarSkip) {
|
||||
if (replyToMsg || replyToStory) {
|
||||
const auto media = replyToMsg ? replyToMsg->media() : nullptr;
|
||||
auto hasPreview = (replyToStory && replyToStory->hasReplyPreview()) || (media && media->hasReplyPreview());
|
||||
if (resolvedMessage || resolvedStory) {
|
||||
const auto media = resolvedMessage ? resolvedMessage->media() : nullptr;
|
||||
auto hasPreview = (media && media->hasReplyPreview())
|
||||
|| (resolvedStory && resolvedStory->hasReplyPreview());
|
||||
if (hasPreview && w < st::msgReplyBarSkip + st::msgReplyBarSize.height()) {
|
||||
hasPreview = false;
|
||||
}
|
||||
|
@ -576,7 +705,7 @@ void HistoryMessageReply::paint(
|
|||
if (hasPreview) {
|
||||
const auto image = media
|
||||
? media->replyPreview()
|
||||
: replyToStory->replyPreview();
|
||||
: resolvedStory->replyPreview();
|
||||
if (image) {
|
||||
auto to = style::rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x);
|
||||
const auto preview = image->pixSingle(
|
||||
|
@ -604,26 +733,26 @@ void HistoryMessageReply::paint(
|
|||
if (w > st::msgReplyBarSkip + previewSkip) {
|
||||
p.setPen(!inBubble
|
||||
? st->msgImgReplyBarColor()
|
||||
: replyToColorKey
|
||||
? HistoryView::FromNameFg(context, replyToColorKey)
|
||||
: _colorKey
|
||||
? HistoryView::FromNameFg(context, _colorKey)
|
||||
: stm->msgServiceFg);
|
||||
replyToName.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip, w + 2 * x);
|
||||
if (replyToVia && w > st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew) {
|
||||
_name.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip, w + 2 * x);
|
||||
if (originalVia && w > st::msgReplyBarSkip + previewSkip + _name.maxWidth() + st::msgServiceFont->spacew) {
|
||||
p.setFont(st::msgServiceFont);
|
||||
p.drawText(x + st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew, y + st::msgReplyPadding.top() + st::msgServiceFont->ascent, replyToVia->text);
|
||||
p.drawText(x + st::msgReplyBarSkip + previewSkip + _name.maxWidth() + st::msgServiceFont->spacew, y + st::msgReplyPadding.top() + st::msgServiceFont->ascent, originalVia->text);
|
||||
}
|
||||
|
||||
p.setPen(inBubble
|
||||
? stm->historyTextFg
|
||||
: st->msgImgReplyBarColor());
|
||||
holder->prepareCustomEmojiPaint(p, context, replyToText);
|
||||
holder->prepareCustomEmojiPaint(p, context, _text);
|
||||
auto replyToTextPosition = QPoint(
|
||||
x + st::msgReplyBarSkip + previewSkip,
|
||||
y + st::msgReplyPadding.top() + st::msgServiceNameFont->height);
|
||||
const auto replyToTextPalette = &(inBubble
|
||||
? stm->replyTextPalette
|
||||
: st->imgReplyTextPalette());
|
||||
if (storyReply) {
|
||||
if (_fields.storyId) {
|
||||
st::dialogsMiniReplyStory.icon.icon.paint(
|
||||
p,
|
||||
replyToTextPosition,
|
||||
|
@ -634,7 +763,7 @@ void HistoryMessageReply::paint(
|
|||
+ st::dialogsMiniReplyStory.icon.icon.width(),
|
||||
0);
|
||||
}
|
||||
replyToText.draw(p, {
|
||||
_text.draw(p, {
|
||||
.position = replyToTextPosition,
|
||||
.availableWidth = w - st::msgReplyBarSkip - previewSkip,
|
||||
.palette = replyToTextPalette,
|
||||
|
@ -657,10 +786,14 @@ void HistoryMessageReply::paint(
|
|||
}
|
||||
}
|
||||
|
||||
void HistoryMessageReply::unloadPersistentAnimation() {
|
||||
_text.unloadPersistentAnimation();
|
||||
}
|
||||
|
||||
QString HistoryMessageReply::statePhrase() const {
|
||||
return (replyToMsgId || replyToStoryId)
|
||||
return ((_fields.messageId || _fields.storyId) && !_deleted)
|
||||
? tr::lng_profile_loading(tr::now)
|
||||
: storyReply
|
||||
: _fields.storyId
|
||||
? tr::lng_deleted_story(tr::now)
|
||||
: tr::lng_deleted_message(tr::now);
|
||||
}
|
||||
|
@ -668,7 +801,7 @@ QString HistoryMessageReply::statePhrase() const {
|
|||
void HistoryMessageReply::refreshReplyToMedia() {
|
||||
replyToDocumentId = 0;
|
||||
replyToWebPageId = 0;
|
||||
if (const auto media = replyToMsg ? replyToMsg->media() : nullptr) {
|
||||
if (const auto media = resolvedMessage ? resolvedMessage->media() : nullptr) {
|
||||
if (const auto document = media->document()) {
|
||||
replyToDocumentId = document->id;
|
||||
} else if (const auto webpage = media->webpage()) {
|
||||
|
|
|
@ -75,7 +75,7 @@ struct HistoryMessageViews : public RuntimeComponent<HistoryMessageViews, Histor
|
|||
};
|
||||
|
||||
struct HistoryMessageSigned : public RuntimeComponent<HistoryMessageSigned, HistoryItem> {
|
||||
QString author;
|
||||
QString postAuthor;
|
||||
bool isAnonymousRank = false;
|
||||
};
|
||||
|
||||
|
@ -123,7 +123,7 @@ struct HistoryMessageForwarded : public RuntimeComponent<HistoryMessageForwarded
|
|||
TimeId originalDate = 0;
|
||||
PeerData *originalSender = nullptr;
|
||||
std::unique_ptr<HiddenSenderInfo> hiddenSenderInfo;
|
||||
QString originalAuthor;
|
||||
QString originalPostAuthor;
|
||||
QString psaType;
|
||||
MsgId originalId = 0;
|
||||
mutable Ui::Text::String text = { 1 };
|
||||
|
@ -226,6 +226,22 @@ private:
|
|||
|
||||
};
|
||||
|
||||
struct ReplyFields {
|
||||
TextWithEntities quote;
|
||||
PeerId externalSenderId = 0;
|
||||
QString externalSenderName;
|
||||
QString externalPostAuthor;
|
||||
PeerId externalPeerId = 0;
|
||||
MsgId messageId = 0;
|
||||
MsgId topMessageId = 0;
|
||||
StoryId storyId = 0;
|
||||
bool topicPost = false;
|
||||
};
|
||||
|
||||
[[nodiscard]] ReplyFields ReplyFieldsFromMTP(
|
||||
not_null<History*> history,
|
||||
const MTPMessageReplyHeader &reply);
|
||||
|
||||
struct HistoryMessageReply
|
||||
: public RuntimeComponent<HistoryMessageReply, HistoryItem> {
|
||||
HistoryMessageReply();
|
||||
|
@ -238,17 +254,25 @@ struct HistoryMessageReply
|
|||
|
||||
static constexpr auto kBarAlpha = 230. / 255.;
|
||||
|
||||
void set(ReplyFields fields);
|
||||
|
||||
void updateFields(
|
||||
not_null<HistoryItem*> holder,
|
||||
MsgId messageId,
|
||||
MsgId topMessageId,
|
||||
bool topicPost);
|
||||
bool updateData(not_null<HistoryItem*> holder, bool force = false);
|
||||
|
||||
// Must be called before destructor.
|
||||
void clearData(not_null<HistoryItem*> holder);
|
||||
|
||||
[[nodiscard]] PeerData *replyToFrom(not_null<HistoryItem*> holder) const;
|
||||
[[nodiscard]] QString replyToFromName(
|
||||
not_null<HistoryItem*> holder) const;
|
||||
[[nodiscard]] QString replyToFromName(not_null<PeerData*> peer) const;
|
||||
[[nodiscard]] PeerData *sender(not_null<HistoryItem*> holder) const;
|
||||
[[nodiscard]] QString senderName(not_null<HistoryItem*> holder) const;
|
||||
[[nodiscard]] QString senderName(not_null<PeerData*> peer) const;
|
||||
[[nodiscard]] bool isNameUpdated(not_null<HistoryItem*> holder) const;
|
||||
void updateName(not_null<HistoryItem*> holder) const;
|
||||
void updateName(
|
||||
not_null<HistoryItem*> holder,
|
||||
std::optional<PeerData*> resolvedSender = std::nullopt) const;
|
||||
void resize(int width) const;
|
||||
void itemRemoved(
|
||||
not_null<HistoryItem*> holder,
|
||||
|
@ -265,52 +289,63 @@ struct HistoryMessageReply
|
|||
int y,
|
||||
int w,
|
||||
bool inBubble) const;
|
||||
void unloadPersistentAnimation();
|
||||
|
||||
[[nodiscard]] PeerId replyToPeer() const {
|
||||
return replyToPeerId;
|
||||
[[nodiscard]] PeerId colorKey() const {
|
||||
return _colorKey;
|
||||
}
|
||||
[[nodiscard]] MsgId replyToId() const {
|
||||
return replyToMsgId;
|
||||
[[nodiscard]] PeerId externalPeerId() const {
|
||||
return _fields.externalPeerId;
|
||||
}
|
||||
[[nodiscard]] MsgId replyToTop() const {
|
||||
return replyToMsgTop;
|
||||
[[nodiscard]] MsgId messageId() const {
|
||||
return _fields.messageId;
|
||||
}
|
||||
[[nodiscard]] int replyToWidth() const {
|
||||
return maxReplyWidth;
|
||||
[[nodiscard]] StoryId storyId() const {
|
||||
return _fields.storyId;
|
||||
}
|
||||
[[nodiscard]] ClickHandlerPtr replyToLink() const {
|
||||
return replyToLnk;
|
||||
[[nodiscard]] MsgId topMessageId() const {
|
||||
return _fields.topMessageId;
|
||||
}
|
||||
[[nodiscard]] int maxWidth() const {
|
||||
return _maxWidth;
|
||||
}
|
||||
[[nodiscard]] ClickHandlerPtr link() const {
|
||||
return _link;
|
||||
}
|
||||
[[nodiscard]] bool topicPost() const {
|
||||
return _fields.topicPost;
|
||||
}
|
||||
[[nodiscard]] QString statePhrase() const;
|
||||
void setReplyToLinkFrom(not_null<HistoryItem*> holder);
|
||||
|
||||
void setLinkFrom(not_null<HistoryItem*> holder);
|
||||
void setTopMessageId(MsgId topMessageId);
|
||||
|
||||
void refreshReplyToMedia();
|
||||
|
||||
PeerId replyToPeerId = 0;
|
||||
MsgId replyToMsgId = 0;
|
||||
MsgId replyToMsgTop = 0;
|
||||
StoryId replyToStoryId = 0;
|
||||
using ColorKey = PeerId;
|
||||
ColorKey replyToColorKey = 0;
|
||||
DocumentId replyToDocumentId = 0;
|
||||
WebPageId replyToWebPageId = 0;
|
||||
ReplyToMessagePointer replyToMsg;
|
||||
ReplyToStoryPointer replyToStory;
|
||||
std::unique_ptr<HistoryMessageVia> replyToVia;
|
||||
ReplyToMessagePointer resolvedMessage;
|
||||
ReplyToStoryPointer resolvedStory;
|
||||
std::unique_ptr<HistoryMessageVia> originalVia;
|
||||
std::unique_ptr<Ui::SpoilerAnimation> spoiler;
|
||||
ClickHandlerPtr replyToLnk;
|
||||
mutable Ui::Text::String replyToName, replyToText;
|
||||
mutable int replyToVersion = 0;
|
||||
mutable int maxReplyWidth = 0;
|
||||
int toWidth = 0;
|
||||
bool topicPost = false;
|
||||
bool storyReply = false;
|
||||
|
||||
struct final {
|
||||
struct {
|
||||
mutable std::unique_ptr<Ui::RippleAnimation> animation;
|
||||
QPoint lastPoint;
|
||||
} ripple;
|
||||
|
||||
private:
|
||||
ReplyFields _fields;
|
||||
PeerId _colorKey = 0;
|
||||
ClickHandlerPtr _link;
|
||||
mutable Ui::Text::String _name;
|
||||
mutable Ui::Text::String _text;
|
||||
mutable PeerData *_externalSender = nullptr;
|
||||
mutable int _maxWidth = 0;
|
||||
mutable int _nameVersion = 0;
|
||||
bool _deleted = false;
|
||||
|
||||
};
|
||||
|
||||
struct HistoryMessageTranslation
|
||||
|
|
|
@ -192,13 +192,14 @@ bool ShouldSendSilent(
|
|||
&& peer->session().settings().supportAllSilent());
|
||||
}
|
||||
|
||||
HistoryItem *LookupReplyTo(not_null<History*> history, MsgId replyToId) {
|
||||
const auto &owner = history->owner();
|
||||
return owner.message(history->peer, replyToId);
|
||||
HistoryItem *LookupReplyTo(not_null<History*> history, FullMsgId replyTo) {
|
||||
return history->owner().message(replyTo);
|
||||
}
|
||||
|
||||
MsgId LookupReplyToTop(HistoryItem *replyTo) {
|
||||
return replyTo ? replyTo->replyToTop() : 0;
|
||||
MsgId LookupReplyToTop(not_null<History*> history, HistoryItem *replyTo) {
|
||||
return (replyTo && replyTo->history() == history)
|
||||
? replyTo->replyToTop()
|
||||
: 0;
|
||||
}
|
||||
|
||||
bool LookupReplyIsTopicPost(HistoryItem *replyTo) {
|
||||
|
@ -360,27 +361,21 @@ MTPMessageReplyHeader NewMessageReplyHeader(const Api::SendAction &action) {
|
|||
MTP_long(peerToUser(replyTo.storyId.peer).bare),
|
||||
MTP_int(replyTo.storyId.story));
|
||||
}
|
||||
const auto to = LookupReplyTo(action.history, replyTo.msgId);
|
||||
if (const auto replyToTop = LookupReplyToTop(to)) {
|
||||
using Flag = MTPDmessageReplyHeader::Flag;
|
||||
return MTP_messageReplyHeader(
|
||||
MTP_flags(Flag::f_reply_to_top_id
|
||||
| (LookupReplyIsTopicPost(to)
|
||||
? Flag::f_forum_topic
|
||||
: Flag(0))),
|
||||
MTP_int(replyTo.msgId),
|
||||
MTPPeer(),
|
||||
MTPMessageFwdHeader(), // reply_header
|
||||
MTP_int(replyToTop),
|
||||
MTPstring(), // quote_text
|
||||
MTPVector<MTPMessageEntity>()); // quote_entities
|
||||
}
|
||||
using Flag = MTPDmessageReplyHeader::Flag;
|
||||
const auto historyPeer = action.history->peer->id;
|
||||
const auto externalPeerId = (replyTo.messageId.peer == historyPeer)
|
||||
? PeerId()
|
||||
: replyTo.messageId.peer;
|
||||
const auto to = LookupReplyTo(action.history, replyTo.messageId);
|
||||
const auto replyToTop = LookupReplyToTop(action.history, to);
|
||||
return MTP_messageReplyHeader(
|
||||
MTP_flags(0),
|
||||
MTP_int(replyTo.msgId),
|
||||
MTPPeer(), // reply_to_peer_id
|
||||
MTP_flags(Flag::f_reply_to_msg_id
|
||||
| (replyToTop ? Flag::f_reply_to_top_id : Flag())
|
||||
| (externalPeerId ? Flag::f_reply_to_peer_id : Flag())),
|
||||
MTP_int(replyTo.messageId.msg),
|
||||
peerToMTP(externalPeerId),
|
||||
MTPMessageFwdHeader(), // reply_header
|
||||
MTPint(), // reply_to_top_id
|
||||
MTP_int(replyToTop), // reply_to_top_id
|
||||
MTPstring(), // quote_text
|
||||
MTPVector<MTPMessageEntity>()); // quote_entities
|
||||
}
|
||||
|
|
|
@ -85,8 +85,10 @@ void RequestDependentMessageStory(
|
|||
const Api::SendOptions &options);
|
||||
[[nodiscard]] HistoryItem *LookupReplyTo(
|
||||
not_null<History*> history,
|
||||
MsgId replyToId);
|
||||
[[nodiscard]] MsgId LookupReplyToTop(HistoryItem *replyTo);
|
||||
FullMsgId replyToId);
|
||||
[[nodiscard]] MsgId LookupReplyToTop(
|
||||
not_null<History*> history,
|
||||
HistoryItem *replyTo);
|
||||
[[nodiscard]] bool LookupReplyIsTopicPost(HistoryItem *replyTo);
|
||||
|
||||
struct SendingErrorRequest {
|
||||
|
|
|
@ -517,7 +517,7 @@ HistoryWidget::HistoryWidget(
|
|||
if (!_peer || isRecording()) {
|
||||
return false;
|
||||
}
|
||||
const auto replyTo = (_replyToId && !_editMsgId)
|
||||
const auto replyTo = (_replyTo && !_editMsgId)
|
||||
? _replyEditMsg
|
||||
: 0;
|
||||
const auto topic = replyTo ? replyTo->topic() : nullptr;
|
||||
|
@ -848,9 +848,8 @@ HistoryWidget::HistoryWidget(
|
|||
) | rpl::filter([=](const Api::SendAction &action) {
|
||||
return (action.history == _history);
|
||||
}) | rpl::start_with_next([=](const Api::SendAction &action) {
|
||||
const auto lastKeyboardUsed = lastForceReplyReplied(FullMsgId(
|
||||
action.history->peer->id,
|
||||
action.replyTo.msgId));
|
||||
const auto lastKeyboardUsed = lastForceReplyReplied(
|
||||
action.replyTo.messageId);
|
||||
if (action.replaceMediaOf) {
|
||||
} else if (action.options.scheduled) {
|
||||
cancelReply(lastKeyboardUsed);
|
||||
|
@ -909,7 +908,7 @@ Dialogs::EntryState HistoryWidget::computeDialogsEntryState() const {
|
|||
return Dialogs::EntryState{
|
||||
.key = _history,
|
||||
.section = Dialogs::EntryState::Section::History,
|
||||
.currentReplyToId = replyToId(),
|
||||
.currentReplyTo = replyTo(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1354,7 +1353,7 @@ void HistoryWidget::insertHashtagOrBotCommand(
|
|||
|
||||
// Send bot command at once, if it was not inserted by pressing Tab.
|
||||
if (str.at(0) == '/' && method != FieldAutocomplete::ChooseMethod::ByTab) {
|
||||
sendBotCommand({ _peer, str, FullMsgId(), replyToId() });
|
||||
sendBotCommand({ _peer, str, FullMsgId(), replyTo() });
|
||||
session().api().finishForwarding(prepareSendAction({}));
|
||||
setFieldText(_field->getTextWithTagsPart(_field->textCursor().position()));
|
||||
} else {
|
||||
|
@ -1663,21 +1662,22 @@ void HistoryWidget::saveFieldToHistoryLocalDraft() {
|
|||
if (_editMsgId) {
|
||||
_history->setLocalEditDraft(std::make_unique<Data::Draft>(
|
||||
_field,
|
||||
_editMsgId,
|
||||
topicRootId,
|
||||
FullReplyTo{
|
||||
.messageId = FullMsgId(_history->peer->id, _editMsgId),
|
||||
.topicRootId = topicRootId,
|
||||
},
|
||||
_previewState,
|
||||
_saveEditMsgRequestId));
|
||||
} else {
|
||||
if (_replyToId || !_field->empty()) {
|
||||
if (_replyTo || !_field->empty()) {
|
||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||
_field,
|
||||
_replyToId,
|
||||
topicRootId,
|
||||
_replyTo,
|
||||
_previewState));
|
||||
} else {
|
||||
_history->clearLocalDraft({});
|
||||
_history->clearLocalDraft(topicRootId);
|
||||
}
|
||||
_history->clearLocalEditDraft({});
|
||||
_history->clearLocalEditDraft(topicRootId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1779,8 +1779,7 @@ bool HistoryWidget::notify_switchInlineBotButtonReceived(
|
|||
};
|
||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||
textWithTags,
|
||||
0, // replyTo
|
||||
0, // topicRootId
|
||||
FullReplyTo(),
|
||||
cursor,
|
||||
Data::PreviewState::Allowed));
|
||||
applyDraft();
|
||||
|
@ -1885,7 +1884,7 @@ bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
|||
? _history->localDraft({})
|
||||
: nullptr;
|
||||
auto fieldAvailable = canWriteMessage();
|
||||
const auto editMsgId = editDraft ? editDraft->msgId : 0;
|
||||
const auto editMsgId = editDraft ? editDraft->reply.messageId.msg : 0;
|
||||
if (_voiceRecordBar->isActive() || (!_canSendTexts && !editMsgId)) {
|
||||
if (!_canSendTexts) {
|
||||
clearFieldText(0, fieldHistoryAction);
|
||||
|
@ -1898,7 +1897,7 @@ bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
|||
clearFieldText(0, fieldHistoryAction);
|
||||
setInnerFocus();
|
||||
_processingReplyItem = _replyEditMsg = nullptr;
|
||||
_processingReplyId = _replyToId = 0;
|
||||
_processingReplyTo = _replyTo = FullReplyTo();
|
||||
setEditMsgId(0);
|
||||
if (fieldWillBeHiddenAfterEdit) {
|
||||
updateControlsVisibility();
|
||||
|
@ -1916,7 +1915,7 @@ bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
|||
| TextUpdateEvent::SendTyping;
|
||||
|
||||
_processingReplyItem = _replyEditMsg = nullptr;
|
||||
_processingReplyId = _replyToId = 0;
|
||||
_processingReplyTo = _replyTo = FullReplyTo();
|
||||
setEditMsgId(editMsgId);
|
||||
updateCmdStartShown();
|
||||
updateControlsVisibility();
|
||||
|
@ -1929,7 +1928,7 @@ bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
|||
}
|
||||
} else if (!readyToForward()) {
|
||||
const auto draft = _history->localDraft({});
|
||||
_processingReplyId = draft ? draft->msgId : MsgId();
|
||||
_processingReplyTo = draft ? draft->reply : FullReplyTo();
|
||||
processReply();
|
||||
}
|
||||
|
||||
|
@ -2147,7 +2146,8 @@ void HistoryWidget::showHistory(
|
|||
|
||||
_saveEditMsgRequestId = 0;
|
||||
_processingReplyItem = _replyEditMsg = nullptr;
|
||||
_processingReplyId = _editMsgId = _replyToId = 0;
|
||||
_processingReplyTo = _replyTo = FullReplyTo();
|
||||
_editMsgId = MsgId();
|
||||
_canReplaceMedia = false;
|
||||
_photoEditMedia = nullptr;
|
||||
updateReplaceMediaButton();
|
||||
|
@ -2461,10 +2461,13 @@ void HistoryWidget::registerDraftSource() {
|
|||
if (!_history) {
|
||||
return;
|
||||
}
|
||||
const auto peerId = _history->peer->id;
|
||||
const auto editMsgId = _editMsgId;
|
||||
const auto draft = [=] {
|
||||
return Storage::MessageDraft{
|
||||
editMsgId ? editMsgId : _replyToId,
|
||||
(editMsgId
|
||||
? FullReplyTo{ FullMsgId(peerId, editMsgId) }
|
||||
: _replyTo),
|
||||
_field->getTextWithTags(),
|
||||
_previewState,
|
||||
};
|
||||
|
@ -2901,7 +2904,11 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
}
|
||||
updateFieldPlaceholder();
|
||||
|
||||
if (_editMsgId || _replyToId || readyToForward() || (_previewData && _previewData->pendingTill >= 0) || _kbReplyTo) {
|
||||
if (_editMsgId
|
||||
|| _replyTo
|
||||
|| readyToForward()
|
||||
|| (_previewData && _previewData->pendingTill >= 0)
|
||||
|| _kbReplyTo) {
|
||||
if (_fieldBarCancel->isHidden()) {
|
||||
_fieldBarCancel->show();
|
||||
updateControlsGeometry();
|
||||
|
@ -2938,7 +2945,7 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
_botMenuButton->hide();
|
||||
}
|
||||
_kbScroll->hide();
|
||||
if (_replyToId || readyToForward() || _kbReplyTo) {
|
||||
if (_replyTo || readyToForward() || _kbReplyTo) {
|
||||
if (_fieldBarCancel->isHidden()) {
|
||||
_fieldBarCancel->show();
|
||||
updateControlsGeometry();
|
||||
|
@ -3889,7 +3896,7 @@ void HistoryWidget::hideSelectorControlsAnimated() {
|
|||
Api::SendAction HistoryWidget::prepareSendAction(
|
||||
Api::SendOptions options) const {
|
||||
auto result = Api::SendAction(_history, options);
|
||||
result.replyTo = { .msgId = replyToId() };
|
||||
result.replyTo = replyTo();
|
||||
result.options.sendAs = _sendAs
|
||||
? _history->session().sendAsPeers().resolveChosen(
|
||||
_history->peer).get()
|
||||
|
@ -4337,7 +4344,7 @@ void HistoryWidget::updateOverStates(QPoint pos) {
|
|||
_field->y() - st::historySendPadding - st::historyReplyHeight,
|
||||
width() - skip - _fieldBarCancel->width(),
|
||||
st::historyReplyHeight);
|
||||
auto inReplyEditForward = (_editMsgId || replyToId() || isReadyToForward)
|
||||
auto inReplyEditForward = (_editMsgId || replyTo() || isReadyToForward)
|
||||
&& replyEditForwardInfoRect.contains(pos);
|
||||
auto inPhotoEdit = inReplyEditForward
|
||||
&& _photoEditMedia
|
||||
|
@ -4387,9 +4394,9 @@ void HistoryWidget::sendBotCommand(const Bot::SendCommandRequest &request) {
|
|||
return;
|
||||
}
|
||||
|
||||
const auto lastKeyboardUsed = (_keyboard->forMsgId()
|
||||
== FullMsgId(_peer->id, _history->lastKeyboardId))
|
||||
&& (_keyboard->forMsgId() == FullMsgId(_peer->id, request.replyTo));
|
||||
const auto forMsgId = _keyboard->forMsgId();
|
||||
const auto lastKeyboardUsed = (forMsgId == request.replyTo.messageId)
|
||||
&& (forMsgId == FullMsgId(_peer->id, _history->lastKeyboardId));
|
||||
|
||||
// 'bot' may be nullptr in case of sending from FieldAutocomplete.
|
||||
const auto toSend = (request.replyTo/* || !bot*/)
|
||||
|
@ -4398,14 +4405,14 @@ void HistoryWidget::sendBotCommand(const Bot::SendCommandRequest &request) {
|
|||
|
||||
auto message = Api::MessageToSend(prepareSendAction({}));
|
||||
message.textWithTags = { toSend, TextWithTags::Tags() };
|
||||
message.action.replyTo.msgId = request.replyTo
|
||||
message.action.replyTo = request.replyTo
|
||||
? ((!_peer->isUser()/* && (botStatus == 0 || botStatus == 2)*/)
|
||||
? request.replyTo
|
||||
: replyToId())
|
||||
: 0;
|
||||
: replyTo())
|
||||
: FullReplyTo();
|
||||
session().api().sendMessage(std::move(message));
|
||||
if (request.replyTo) {
|
||||
if (_replyToId == request.replyTo) {
|
||||
if (_replyTo == request.replyTo) {
|
||||
cancelReply();
|
||||
saveCloudDraft();
|
||||
}
|
||||
|
@ -4418,18 +4425,25 @@ void HistoryWidget::sendBotCommand(const Bot::SendCommandRequest &request) {
|
|||
setInnerFocus();
|
||||
}
|
||||
|
||||
void HistoryWidget::hideSingleUseKeyboard(PeerData *peer, MsgId replyTo) {
|
||||
if (!_peer || _peer != peer) return;
|
||||
void HistoryWidget::hideSingleUseKeyboard(FullMsgId replyToId) {
|
||||
if (!_peer || _peer->id != replyToId.peer) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool lastKeyboardUsed = (_keyboard->forMsgId() == FullMsgId(_peer->id, _history->lastKeyboardId))
|
||||
&& (_keyboard->forMsgId() == FullMsgId(_peer->id, replyTo));
|
||||
if (replyTo) {
|
||||
if (_replyToId == replyTo) {
|
||||
bool lastKeyboardUsed = (_keyboard->forMsgId() == replyToId)
|
||||
&& (_keyboard->forMsgId()
|
||||
== FullMsgId(_peer->id, _history->lastKeyboardId));
|
||||
if (replyToId) {
|
||||
if (_replyTo.messageId == replyToId) {
|
||||
cancelReply();
|
||||
saveCloudDraft();
|
||||
}
|
||||
if (_keyboard->singleUse() && _keyboard->hasMarkup() && lastKeyboardUsed) {
|
||||
if (_kbShown) toggleKeyboard(false);
|
||||
if (_keyboard->singleUse()
|
||||
&& _keyboard->hasMarkup()
|
||||
&& lastKeyboardUsed) {
|
||||
if (_kbShown) {
|
||||
toggleKeyboard(false);
|
||||
}
|
||||
_history->lastKeyboardUsed = true;
|
||||
}
|
||||
}
|
||||
|
@ -4772,7 +4786,7 @@ void HistoryWidget::toggleKeyboard(bool manual) {
|
|||
_field->setMaxHeight(computeMaxFieldHeight());
|
||||
|
||||
_kbReplyTo = nullptr;
|
||||
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_editMsgId && !_replyToId) {
|
||||
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_editMsgId && !_replyTo) {
|
||||
_fieldBarCancel->hide();
|
||||
updateMouseTracking();
|
||||
}
|
||||
|
@ -4797,7 +4811,7 @@ void HistoryWidget::toggleKeyboard(bool manual) {
|
|||
_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard->forceReply())
|
||||
? session().data().message(_keyboard->forMsgId())
|
||||
: nullptr;
|
||||
if (_kbReplyTo && !_editMsgId && !_replyToId && fieldEnabled) {
|
||||
if (_kbReplyTo && !_editMsgId && !_replyTo && fieldEnabled) {
|
||||
updateReplyToName();
|
||||
updateReplyEditText(_kbReplyTo);
|
||||
}
|
||||
|
@ -4817,7 +4831,7 @@ void HistoryWidget::toggleKeyboard(bool manual) {
|
|||
_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard->forceReply())
|
||||
? session().data().message(_keyboard->forMsgId())
|
||||
: nullptr;
|
||||
if (_kbReplyTo && !_editMsgId && !_replyToId) {
|
||||
if (_kbReplyTo && !_editMsgId && !_replyTo) {
|
||||
updateReplyToName();
|
||||
updateReplyEditText(_kbReplyTo);
|
||||
}
|
||||
|
@ -5589,11 +5603,11 @@ void HistoryWidget::itemRemoved(not_null<const HistoryItem*> item) {
|
|||
if (item == _replyEditMsg && _editMsgId) {
|
||||
cancelEdit();
|
||||
}
|
||||
if (item == _replyEditMsg && _replyToId) {
|
||||
if (item == _replyEditMsg && _replyTo) {
|
||||
cancelReply();
|
||||
}
|
||||
if (item == _processingReplyItem) {
|
||||
_processingReplyId = 0;
|
||||
_processingReplyTo = {};
|
||||
_processingReplyItem = nullptr;
|
||||
}
|
||||
if (_kbReplyTo && item == _kbReplyTo) {
|
||||
|
@ -5617,8 +5631,12 @@ void HistoryWidget::itemEdited(not_null<HistoryItem*> item) {
|
|||
}
|
||||
}
|
||||
|
||||
MsgId HistoryWidget::replyToId() const {
|
||||
return _replyToId ? _replyToId : (_kbReplyTo ? _kbReplyTo->id : 0);
|
||||
FullReplyTo HistoryWidget::replyTo() const {
|
||||
return _replyTo
|
||||
? _replyTo
|
||||
: _kbReplyTo
|
||||
? FullReplyTo{ _kbReplyTo->fullId() }
|
||||
: FullReplyTo();
|
||||
}
|
||||
|
||||
bool HistoryWidget::hasSavedScroll() const {
|
||||
|
@ -5753,7 +5771,7 @@ void HistoryWidget::updateHistoryGeometry(
|
|||
} else if (writeRestriction().has_value()) {
|
||||
newScrollHeight -= _unblock->height();
|
||||
}
|
||||
if (_editMsgId || replyToId() || readyToForward() || (_previewData && _previewData->pendingTill >= 0)) {
|
||||
if (_editMsgId || replyTo() || readyToForward() || (_previewData && _previewData->pendingTill >= 0)) {
|
||||
newScrollHeight -= st::historyReplyHeight;
|
||||
}
|
||||
if (_kbShown) {
|
||||
|
@ -5991,9 +6009,9 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
const auto wasVisible = _kbShown || _kbReplyTo;
|
||||
const auto wasMsgId = _keyboard->forMsgId();
|
||||
auto changed = false;
|
||||
if ((_replyToId && !_replyEditMsg) || _editMsgId || !_history) {
|
||||
if ((_replyTo && !_replyEditMsg) || _editMsgId || !_history) {
|
||||
changed = _keyboard->updateMarkup(nullptr, force);
|
||||
} else if (_replyToId && _replyEditMsg) {
|
||||
} else if (_replyTo && _replyEditMsg) {
|
||||
changed = _keyboard->updateMarkup(_replyEditMsg, force);
|
||||
} else {
|
||||
const auto keyboardItem = _history->lastKeyboardId
|
||||
|
@ -6010,7 +6028,7 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
_kbScroll->scrollTo({ 0, 0 });
|
||||
}
|
||||
|
||||
bool hasMarkup = _keyboard->hasMarkup(), forceReply = _keyboard->forceReply() && (!_replyToId || !_replyEditMsg);
|
||||
bool hasMarkup = _keyboard->hasMarkup(), forceReply = _keyboard->forceReply() && (!_replyTo || !_replyEditMsg);
|
||||
if (hasMarkup || forceReply) {
|
||||
if (_keyboard->singleUse()
|
||||
&& _keyboard->hasMarkup()
|
||||
|
@ -6019,7 +6037,7 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
&& _history->lastKeyboardUsed) {
|
||||
_history->lastKeyboardHiddenId = _history->lastKeyboardId;
|
||||
}
|
||||
if (!isSearching() && !isBotStart() && !isBlocked() && _canSendMessages && (wasVisible || (_replyToId && _replyEditMsg) || (!HasSendText(_field) && !kbWasHidden()))) {
|
||||
if (!isSearching() && !isBotStart() && !isBlocked() && _canSendMessages && (wasVisible || (_replyTo && _replyEditMsg) || (!HasSendText(_field) && !kbWasHidden()))) {
|
||||
if (!_showAnimation) {
|
||||
if (hasMarkup) {
|
||||
_kbScroll->show();
|
||||
|
@ -6040,7 +6058,7 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
_kbReplyTo = (_peer->isChat() || _peer->isChannel() || _keyboard->forceReply())
|
||||
? session().data().message(_keyboard->forMsgId())
|
||||
: nullptr;
|
||||
if (_kbReplyTo && !_replyToId) {
|
||||
if (_kbReplyTo && !_replyTo) {
|
||||
updateReplyToName();
|
||||
updateReplyEditText(_kbReplyTo);
|
||||
}
|
||||
|
@ -6055,7 +6073,7 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
_field->setMaxHeight(computeMaxFieldHeight());
|
||||
_kbShown = false;
|
||||
_kbReplyTo = nullptr;
|
||||
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyToId) {
|
||||
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyTo) {
|
||||
_fieldBarCancel->hide();
|
||||
updateMouseTracking();
|
||||
}
|
||||
|
@ -6071,7 +6089,7 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
_field->setMaxHeight(computeMaxFieldHeight());
|
||||
_kbShown = false;
|
||||
_kbReplyTo = nullptr;
|
||||
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyToId && !_editMsgId) {
|
||||
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_replyTo && !_editMsgId) {
|
||||
_fieldBarCancel->hide();
|
||||
updateMouseTracking();
|
||||
}
|
||||
|
@ -6093,7 +6111,7 @@ void HistoryWidget::botCallbackSent(not_null<HistoryItem*> item) {
|
|||
|
||||
session().data().requestItemRepaint(item);
|
||||
|
||||
if (_replyToId == item->id) {
|
||||
if (_replyTo.messageId == item->fullId()) {
|
||||
cancelReply();
|
||||
}
|
||||
if (_keyboard->singleUse()
|
||||
|
@ -6114,7 +6132,7 @@ int HistoryWidget::computeMaxFieldHeight() const {
|
|||
- (_groupCallBar ? _groupCallBar->height() : 0)
|
||||
- (_requestsBar ? _requestsBar->height() : 0)
|
||||
- ((_editMsgId
|
||||
|| replyToId()
|
||||
|| replyTo()
|
||||
|| readyToForward()
|
||||
|| (_previewData && _previewData->pendingTill >= 0))
|
||||
? st::historyReplyHeight
|
||||
|
@ -6175,7 +6193,7 @@ bool HistoryWidget::cornerButtonsHas(HistoryView::CornerButtonType type) {
|
|||
void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
||||
const auto isReadyToForward = readyToForward();
|
||||
const auto hasSecondLayer = (_editMsgId
|
||||
|| _replyToId
|
||||
|| _replyTo
|
||||
|| isReadyToForward
|
||||
|| _kbReplyTo);
|
||||
_replyForwardPressed = hasSecondLayer && QRect(
|
||||
|
@ -6201,11 +6219,13 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
|||
} else {
|
||||
_forwardPanel->editOptions(controller()->uiShow());
|
||||
}
|
||||
} else if (replyTo() && replyTo().messageId.peer != _peer->id) {
|
||||
// edit options
|
||||
} else {
|
||||
controller()->showPeerHistory(
|
||||
_peer,
|
||||
Window::SectionShow::Way::Forward,
|
||||
_editMsgId ? _editMsgId : replyToId());
|
||||
_editMsgId ? _editMsgId : replyTo().messageId.msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6235,7 +6255,7 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) {
|
|||
if (item
|
||||
&& _field->empty()
|
||||
&& !_editMsgId
|
||||
&& !_replyToId) {
|
||||
&& !_replyTo) {
|
||||
editMessage(item);
|
||||
return;
|
||||
}
|
||||
|
@ -6303,14 +6323,17 @@ void HistoryWidget::handlePeerMigration() {
|
|||
}
|
||||
|
||||
bool HistoryWidget::replyToPreviousMessage() {
|
||||
if (!_history || _editMsgId || _history->isForum()) {
|
||||
if (!_history
|
||||
|| _editMsgId
|
||||
|| _history->isForum()
|
||||
|| (_replyTo && _replyTo.messageId.peer != _history->peer->id)) {
|
||||
return false;
|
||||
}
|
||||
const auto fullId = FullMsgId(
|
||||
_history->peer->id,
|
||||
_field->isVisible()
|
||||
? _replyToId
|
||||
: _highlighter.latestSingleHighlightedMsgId());
|
||||
(_field->isVisible()
|
||||
? _replyTo.messageId.msg
|
||||
: _highlighter.latestSingleHighlightedMsgId()));
|
||||
if (const auto item = session().data().message(fullId)) {
|
||||
if (const auto view = item->mainView()) {
|
||||
if (const auto previousView = view->previousDisplayedInBlocks()) {
|
||||
|
@ -6334,14 +6357,17 @@ bool HistoryWidget::replyToPreviousMessage() {
|
|||
}
|
||||
|
||||
bool HistoryWidget::replyToNextMessage() {
|
||||
if (!_history || _editMsgId || _history->isForum()) {
|
||||
if (!_history
|
||||
|| _editMsgId
|
||||
|| _history->isForum()
|
||||
|| (_replyTo && _replyTo.messageId.peer != _history->peer->id)) {
|
||||
return false;
|
||||
}
|
||||
const auto fullId = FullMsgId(
|
||||
_history->peer->id,
|
||||
_field->isVisible()
|
||||
? _replyToId
|
||||
: _highlighter.latestSingleHighlightedMsgId());
|
||||
(_field->isVisible()
|
||||
? _replyTo.messageId.msg
|
||||
: _highlighter.latestSingleHighlightedMsgId()));
|
||||
if (const auto item = session().data().message(fullId)) {
|
||||
if (const auto view = item->mainView()) {
|
||||
if (const auto nextView = view->nextDisplayedInBlocks()) {
|
||||
|
@ -7024,17 +7050,19 @@ void HistoryWidget::clearFieldText(
|
|||
setFieldText(TextWithTags(), events, fieldHistoryAction);
|
||||
}
|
||||
|
||||
void HistoryWidget::replyToMessage(FullMsgId itemId) {
|
||||
if (const auto item = session().data().message(itemId)) {
|
||||
replyToMessage(item);
|
||||
void HistoryWidget::replyToMessage(FullReplyTo id) {
|
||||
if (const auto item = session().data().message(id.messageId)) {
|
||||
replyToMessage(item, id.quote);
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
|
||||
void HistoryWidget::replyToMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
TextWithTags quote) {
|
||||
if (isJoinChannel()) {
|
||||
return;
|
||||
}
|
||||
_processingReplyId = item->id;
|
||||
_processingReplyTo = { .messageId = item->fullId(), .quote = quote};
|
||||
_processingReplyItem = item;
|
||||
processReply();
|
||||
}
|
||||
|
@ -7042,14 +7070,13 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
|
|||
void HistoryWidget::processReply() {
|
||||
const auto processContinue = [=] {
|
||||
return crl::guard(_list, [=] {
|
||||
if (!_peer || !_processingReplyId) {
|
||||
if (!_peer || !_processingReplyTo) {
|
||||
return;
|
||||
} else if (!_processingReplyItem) {
|
||||
_processingReplyItem = _peer->owner().message(
|
||||
_peer,
|
||||
_processingReplyId);
|
||||
_processingReplyTo.messageId);
|
||||
if (!_processingReplyItem) {
|
||||
_processingReplyId = 0;
|
||||
_processingReplyTo = {};
|
||||
} else {
|
||||
processReply();
|
||||
}
|
||||
|
@ -7057,16 +7084,16 @@ void HistoryWidget::processReply() {
|
|||
});
|
||||
};
|
||||
const auto processCancel = [=] {
|
||||
_processingReplyId = 0;
|
||||
_processingReplyTo = {};
|
||||
_processingReplyItem = nullptr;
|
||||
};
|
||||
|
||||
if (!_peer || !_processingReplyId) {
|
||||
if (!_peer || !_processingReplyTo) {
|
||||
return processCancel();
|
||||
} else if (!_processingReplyItem) {
|
||||
session().api().requestMessageData(
|
||||
_peer,
|
||||
_processingReplyId,
|
||||
session().data().peer(_processingReplyTo.messageId.peer),
|
||||
_processingReplyTo.messageId.msg,
|
||||
processContinue());
|
||||
return;
|
||||
} else if (_processingReplyItem->history() == _migrated) {
|
||||
|
@ -7107,7 +7134,7 @@ void HistoryWidget::processReply() {
|
|||
}
|
||||
|
||||
void HistoryWidget::setReplyFieldsFromProcessing() {
|
||||
if (!_processingReplyId || !_processingReplyItem) {
|
||||
if (!_processingReplyTo || !_processingReplyItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7116,22 +7143,21 @@ void HistoryWidget::setReplyFieldsFromProcessing() {
|
|||
_composeSearch->hideAnimated();
|
||||
}
|
||||
|
||||
const auto id = base::take(_processingReplyId);
|
||||
const auto id = base::take(_processingReplyTo);
|
||||
const auto item = base::take(_processingReplyItem);
|
||||
if (_editMsgId) {
|
||||
if (const auto localDraft = _history->localDraft({})) {
|
||||
localDraft->msgId = id;
|
||||
localDraft->reply = id;
|
||||
} else {
|
||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||
TextWithTags(),
|
||||
id,
|
||||
MsgId(),
|
||||
MessageCursor(),
|
||||
Data::PreviewState::Allowed));
|
||||
}
|
||||
} else {
|
||||
_replyEditMsg = item;
|
||||
_replyToId = id;
|
||||
_replyTo = id;
|
||||
updateReplyEditText(_replyEditMsg);
|
||||
updateCanSendMessage();
|
||||
updateBotKeyboard();
|
||||
|
@ -7170,11 +7196,10 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
|
|||
_send->clearState();
|
||||
}
|
||||
if (!_editMsgId) {
|
||||
if (_replyToId || !_field->empty()) {
|
||||
if (_replyTo || !_field->empty()) {
|
||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||
_field,
|
||||
_replyToId,
|
||||
MsgId(), // topicRootId
|
||||
_replyTo,
|
||||
_previewState));
|
||||
} else {
|
||||
_history->clearLocalDraft({});
|
||||
|
@ -7198,8 +7223,7 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
|
|||
: Data::PreviewState::EmptyOnEdit;
|
||||
_history->setLocalEditDraft(std::make_unique<Data::Draft>(
|
||||
editData,
|
||||
item->id,
|
||||
MsgId(), // topicRootId
|
||||
FullReplyTo{ item->fullId() },
|
||||
cursor,
|
||||
previewState));
|
||||
applyDraft();
|
||||
|
@ -7261,17 +7285,18 @@ bool HistoryWidget::lastForceReplyReplied(const FullMsgId &replyTo) const {
|
|||
bool HistoryWidget::lastForceReplyReplied() const {
|
||||
return _peer
|
||||
&& _keyboard->forceReply()
|
||||
&& _keyboard->forMsgId() == FullMsgId(_peer->id, _history->lastKeyboardId)
|
||||
&& _keyboard->forMsgId().msg == replyToId();
|
||||
&& _keyboard->forMsgId() == replyTo().messageId
|
||||
&& (_keyboard->forMsgId()
|
||||
== FullMsgId(_peer->id, _history->lastKeyboardId));
|
||||
}
|
||||
|
||||
bool HistoryWidget::cancelReply(bool lastKeyboardUsed) {
|
||||
bool wasReply = false;
|
||||
if (_replyToId) {
|
||||
if (_replyTo) {
|
||||
wasReply = true;
|
||||
|
||||
_processingReplyItem = _replyEditMsg = nullptr;
|
||||
_processingReplyId = _replyToId = 0;
|
||||
_processingReplyTo = _replyTo = FullReplyTo();
|
||||
mouseMoveEvent(0);
|
||||
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_kbReplyTo) {
|
||||
_fieldBarCancel->hide();
|
||||
|
@ -7284,11 +7309,11 @@ bool HistoryWidget::cancelReply(bool lastKeyboardUsed) {
|
|||
updateControlsGeometry();
|
||||
update();
|
||||
} else if (const auto localDraft = (_history ? _history->localDraft({}) : nullptr)) {
|
||||
if (localDraft->msgId) {
|
||||
if (localDraft->reply) {
|
||||
if (localDraft->textWithTags.text.isEmpty()) {
|
||||
_history->clearLocalDraft({});
|
||||
} else {
|
||||
localDraft->msgId = 0;
|
||||
localDraft->reply = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7344,7 +7369,7 @@ void HistoryWidget::cancelEdit() {
|
|||
saveDraft();
|
||||
|
||||
mouseMoveEvent(nullptr);
|
||||
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !replyToId()) {
|
||||
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !replyTo()) {
|
||||
_fieldBarCancel->hide();
|
||||
updateMouseTracking();
|
||||
}
|
||||
|
@ -7376,7 +7401,7 @@ void HistoryWidget::cancelFieldAreaState() {
|
|||
cancelEdit();
|
||||
} else if (readyToForward()) {
|
||||
_history->setForwardDraft(MsgId(), {});
|
||||
} else if (_replyToId) {
|
||||
} else if (_replyTo) {
|
||||
cancelReply();
|
||||
} else if (_kbReplyTo) {
|
||||
toggleKeyboard();
|
||||
|
@ -7512,7 +7537,7 @@ void HistoryWidget::updatePreview() {
|
|||
preview.description,
|
||||
Ui::DialogTextOptions());
|
||||
}
|
||||
} else if (!readyToForward() && !replyToId() && !_editMsgId) {
|
||||
} else if (!readyToForward() && !replyTo() && !_editMsgId) {
|
||||
_fieldBarCancel->hide();
|
||||
updateMouseTracking();
|
||||
}
|
||||
|
@ -7579,7 +7604,7 @@ bool HistoryWidget::updateCanSendMessage() {
|
|||
if (!_peer) {
|
||||
return false;
|
||||
}
|
||||
const auto replyTo = (_replyToId && !_editMsgId) ? _replyEditMsg : 0;
|
||||
const auto replyTo = (_replyTo && !_editMsgId) ? _replyEditMsg : 0;
|
||||
const auto topic = replyTo ? replyTo->topic() : nullptr;
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
|
@ -7657,7 +7682,7 @@ void HistoryWidget::escape() {
|
|||
}
|
||||
} else if (!_fieldAutocomplete->isHidden()) {
|
||||
_fieldAutocomplete->hideAnimated();
|
||||
} else if (_replyToId && _field->getTextWithTags().text.isEmpty()) {
|
||||
} else if (_replyTo && _field->getTextWithTags().text.isEmpty()) {
|
||||
cancelReply();
|
||||
} else if (auto &voice = _voiceRecordBar; voice->isActive()) {
|
||||
voice->showDiscardBox(nullptr, anim::type::normal);
|
||||
|
@ -7752,7 +7777,8 @@ void HistoryWidget::messageDataReceived(
|
|||
MsgId msgId) {
|
||||
if (!_peer || _peer != peer || !msgId) {
|
||||
return;
|
||||
} else if (_editMsgId == msgId || _replyToId == msgId) {
|
||||
} else if (_editMsgId == msgId
|
||||
|| (_replyTo.messageId == FullMsgId(peer->id, msgId))) {
|
||||
updateReplyEditTexts(true);
|
||||
}
|
||||
}
|
||||
|
@ -7775,14 +7801,14 @@ void HistoryWidget::updateReplyEditText(not_null<HistoryItem*> item) {
|
|||
|
||||
void HistoryWidget::updateReplyEditTexts(bool force) {
|
||||
if (!force) {
|
||||
if (_replyEditMsg || (!_editMsgId && !_replyToId)) {
|
||||
if (_replyEditMsg || (!_editMsgId && !_replyTo)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!_replyEditMsg && _peer) {
|
||||
_replyEditMsg = session().data().message(
|
||||
_peer->id,
|
||||
_editMsgId ? _editMsgId : _replyToId);
|
||||
_editMsgId ? _peer->id : _replyTo.messageId.peer,
|
||||
_editMsgId ? _editMsgId : _replyTo.messageId.msg);
|
||||
}
|
||||
if (_replyEditMsg) {
|
||||
const auto media = _replyEditMsg->media();
|
||||
|
@ -7828,7 +7854,7 @@ void HistoryWidget::updateForwarding() {
|
|||
void HistoryWidget::updateReplyToName() {
|
||||
if (_editMsgId) {
|
||||
return;
|
||||
} else if (!_replyEditMsg && (_replyToId || !_kbReplyTo)) {
|
||||
} else if (!_replyEditMsg && (_replyTo || !_kbReplyTo)) {
|
||||
return;
|
||||
}
|
||||
const auto from = [&] {
|
||||
|
@ -7862,8 +7888,8 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
|||
auto backy = _field->y() - st::historySendPadding;
|
||||
auto backh = fieldHeight() + 2 * st::historySendPadding;
|
||||
auto hasForward = readyToForward();
|
||||
auto drawMsgText = (_editMsgId || _replyToId) ? _replyEditMsg : _kbReplyTo;
|
||||
if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
|
||||
auto drawMsgText = (_editMsgId || _replyTo) ? _replyEditMsg : _kbReplyTo;
|
||||
if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
||||
if (!_editMsgId
|
||||
&& drawMsgText
|
||||
&& (_replyToNameVersion
|
||||
|
@ -7898,7 +7924,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
|
|||
});
|
||||
}
|
||||
|
||||
if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
|
||||
if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
|
||||
const auto now = crl::now();
|
||||
const auto paused = p.inactive();
|
||||
const auto pausedSpoiler = paused || On(PowerSaving::kChatSpoiler);
|
||||
|
@ -8097,7 +8123,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
|
|||
const auto restrictionHidden = fieldOrDisabledShown()
|
||||
|| isRecording();
|
||||
if (restrictionHidden
|
||||
|| replyToId()
|
||||
|| replyTo()
|
||||
|| readyToForward()
|
||||
|| _kbShown) {
|
||||
drawField(p, clip);
|
||||
|
|
|
@ -182,12 +182,14 @@ public:
|
|||
MessageIdsList getSelectedItems() const;
|
||||
void itemEdited(not_null<HistoryItem*> item);
|
||||
|
||||
void replyToMessage(FullMsgId itemId);
|
||||
void replyToMessage(not_null<HistoryItem*> item);
|
||||
void replyToMessage(FullReplyTo id);
|
||||
void replyToMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
TextWithTags quote = {});
|
||||
void editMessage(FullMsgId itemId);
|
||||
void editMessage(not_null<HistoryItem*> item);
|
||||
|
||||
MsgId replyToId() const;
|
||||
[[nodiscard]] FullReplyTo replyTo() const;
|
||||
bool lastForceReplyReplied(const FullMsgId &replyTo) const;
|
||||
bool lastForceReplyReplied() const;
|
||||
bool cancelReply(bool lastKeyboardUsed = false);
|
||||
|
@ -204,7 +206,7 @@ public:
|
|||
void escape();
|
||||
|
||||
void sendBotCommand(const Bot::SendCommandRequest &request);
|
||||
void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo);
|
||||
void hideSingleUseKeyboard(FullMsgId replyToId);
|
||||
bool insertBotCommand(const QString &cmd);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *e) override;
|
||||
|
@ -633,11 +635,11 @@ private:
|
|||
void searchInChat();
|
||||
|
||||
MTP::Sender _api;
|
||||
MsgId _replyToId = 0;
|
||||
FullReplyTo _replyTo;
|
||||
Ui::Text::String _replyToName;
|
||||
int _replyToNameVersion = 0;
|
||||
|
||||
MsgId _processingReplyId = 0;
|
||||
FullReplyTo _processingReplyTo;
|
||||
HistoryItem *_processingReplyItem = nullptr;
|
||||
|
||||
MsgId _editMsgId = 0;
|
||||
|
|
|
@ -353,7 +353,7 @@ public:
|
|||
void init();
|
||||
|
||||
void editMessage(FullMsgId id, bool photoEditAllowed = false);
|
||||
void replyToMessage(FullMsgId id);
|
||||
void replyToMessage(FullReplyTo id);
|
||||
void updateForwarding(
|
||||
Data::Thread *thread,
|
||||
Data::ResolvedForwardDraft items);
|
||||
|
@ -367,7 +367,7 @@ public:
|
|||
[[nodiscard]] bool isEditingMessage() const;
|
||||
[[nodiscard]] bool readyToForward() const;
|
||||
[[nodiscard]] const HistoryItemsList &forwardItems() const;
|
||||
[[nodiscard]] FullMsgId replyingToMessage() const;
|
||||
[[nodiscard]] FullReplyTo replyingToMessage() const;
|
||||
[[nodiscard]] FullMsgId editMsgId() const;
|
||||
[[nodiscard]] rpl::producer<FullMsgId> editMsgIdValue() const;
|
||||
[[nodiscard]] rpl::producer<FullMsgId> scrollToItemRequests() const;
|
||||
|
@ -375,7 +375,7 @@ public:
|
|||
[[nodiscard]] MessageToEdit queryToEdit();
|
||||
[[nodiscard]] WebPageId webPageId() const;
|
||||
|
||||
[[nodiscard]] MsgId getDraftMessageId() const;
|
||||
[[nodiscard]] FullReplyTo getDraftReply() const;
|
||||
[[nodiscard]] rpl::producer<> editCancelled() const {
|
||||
return _editCancelled.events();
|
||||
}
|
||||
|
@ -425,7 +425,7 @@ private:
|
|||
rpl::lifetime _previewLifetime;
|
||||
|
||||
rpl::variable<FullMsgId> _editMsgId;
|
||||
rpl::variable<FullMsgId> _replyToId;
|
||||
rpl::variable<FullReplyTo> _replyTo;
|
||||
std::unique_ptr<ForwardPanel> _forwardPanel;
|
||||
rpl::producer<> _toForwardUpdated;
|
||||
|
||||
|
@ -508,14 +508,14 @@ void FieldHeader::init() {
|
|||
|
||||
_editMsgId.value(
|
||||
) | rpl::start_with_next([=](FullMsgId value) {
|
||||
const auto shown = value ? value : _replyToId.current();
|
||||
const auto shown = value ? value : _replyTo.current().messageId;
|
||||
setShownMessage(_data->message(shown));
|
||||
}, lifetime());
|
||||
|
||||
_replyToId.value(
|
||||
) | rpl::start_with_next([=](FullMsgId value) {
|
||||
_replyTo.value(
|
||||
) | rpl::start_with_next([=](const FullReplyTo &value) {
|
||||
if (!_editMsgId.current()) {
|
||||
setShownMessage(_data->message(value));
|
||||
setShownMessage(_data->message(value.messageId));
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
|
@ -529,7 +529,7 @@ void FieldHeader::init() {
|
|||
if (_editMsgId.current() == update.item->fullId()) {
|
||||
_editCancelled.fire({});
|
||||
}
|
||||
if (_replyToId.current() == update.item->fullId()) {
|
||||
if (_replyTo.current().messageId == update.item->fullId()) {
|
||||
_replyCancelled.fire({});
|
||||
}
|
||||
} else {
|
||||
|
@ -545,7 +545,7 @@ void FieldHeader::init() {
|
|||
_editCancelled.fire({});
|
||||
} else if (readyToForward()) {
|
||||
_forwardCancelled.fire({});
|
||||
} else if (_replyToId.current()) {
|
||||
} else if (_replyTo.current()) {
|
||||
_replyCancelled.fire({});
|
||||
}
|
||||
updateVisible();
|
||||
|
@ -624,7 +624,7 @@ void FieldHeader::init() {
|
|||
} else {
|
||||
auto id = isEditingMessage()
|
||||
? _editMsgId.current()
|
||||
: replyingToMessage();
|
||||
: replyingToMessage().messageId;
|
||||
_scrollToItemRequests.fire(std::move(id));
|
||||
}
|
||||
}
|
||||
|
@ -692,16 +692,18 @@ void FieldHeader::setShownMessage(HistoryItem *item) {
|
|||
}
|
||||
|
||||
void FieldHeader::resolveMessageData() {
|
||||
const auto id = (isEditingMessage() ? _editMsgId : _replyToId).current();
|
||||
const auto id = isEditingMessage()
|
||||
? _editMsgId.current()
|
||||
: _replyTo.current().messageId;
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
const auto peer = _data->peer(id.peer);
|
||||
const auto itemId = id.msg;
|
||||
const auto callback = crl::guard(this, [=] {
|
||||
const auto now = (isEditingMessage()
|
||||
? _editMsgId
|
||||
: _replyToId).current();
|
||||
const auto now = isEditingMessage()
|
||||
? _editMsgId.current()
|
||||
: _replyTo.current().messageId;
|
||||
if (now == id && !_shownMessage) {
|
||||
if (const auto message = _data->message(peer, itemId)) {
|
||||
setShownMessage(message);
|
||||
|
@ -950,8 +952,8 @@ const HistoryItemsList &FieldHeader::forwardItems() const {
|
|||
return _forwardPanel->items();
|
||||
}
|
||||
|
||||
FullMsgId FieldHeader::replyingToMessage() const {
|
||||
return _replyToId.current();
|
||||
FullReplyTo FieldHeader::replyingToMessage() const {
|
||||
return _replyTo.current();
|
||||
}
|
||||
|
||||
bool FieldHeader::hasPreview() const {
|
||||
|
@ -962,8 +964,10 @@ WebPageId FieldHeader::webPageId() const {
|
|||
return hasPreview() ? _preview.data->id : CancelledWebPageId;
|
||||
}
|
||||
|
||||
MsgId FieldHeader::getDraftMessageId() const {
|
||||
return (isEditingMessage() ? _editMsgId : _replyToId).current().msg;
|
||||
FullReplyTo FieldHeader::getDraftReply() const {
|
||||
return isEditingMessage()
|
||||
? FullReplyTo{ _editMsgId.current() }
|
||||
: _replyTo.current();
|
||||
}
|
||||
|
||||
void FieldHeader::updateControlsGeometry(QSize size) {
|
||||
|
@ -992,8 +996,8 @@ void FieldHeader::editMessage(FullMsgId id, bool photoEditAllowed) {
|
|||
update();
|
||||
}
|
||||
|
||||
void FieldHeader::replyToMessage(FullMsgId id) {
|
||||
_replyToId = id;
|
||||
void FieldHeader::replyToMessage(FullReplyTo id) {
|
||||
_replyTo = id;
|
||||
}
|
||||
|
||||
void FieldHeader::updateForwarding(
|
||||
|
@ -1156,6 +1160,7 @@ void ComposeControls::setHistory(SetHistoryArgs &&args) {
|
|||
}
|
||||
unregisterDraftSources();
|
||||
_history = history;
|
||||
_topicRootId = args.topicRootId;
|
||||
_historyLifetime.destroy();
|
||||
_header->setHistory(args);
|
||||
registerDraftSource();
|
||||
|
@ -1193,8 +1198,10 @@ void ComposeControls::setHistory(SetHistoryArgs &&args) {
|
|||
orderControls();
|
||||
}
|
||||
|
||||
void ComposeControls::setCurrentDialogsEntryState(Dialogs::EntryState state) {
|
||||
void ComposeControls::setCurrentDialogsEntryState(
|
||||
Dialogs::EntryState state) {
|
||||
unregisterDraftSources();
|
||||
state.currentReplyTo.topicRootId = _topicRootId;
|
||||
_currentDialogsEntryState = state;
|
||||
updateForwarding();
|
||||
registerDraftSource();
|
||||
|
@ -1472,16 +1479,12 @@ void ComposeControls::saveFieldToHistoryLocalDraft() {
|
|||
if (!_history || !key) {
|
||||
return;
|
||||
}
|
||||
const auto id = _header->getDraftMessageId();
|
||||
const auto id = _header->getDraftReply();
|
||||
if (_preview && (id || !_field->empty())) {
|
||||
const auto key = draftKeyCurrent();
|
||||
_history->setDraft(
|
||||
key,
|
||||
std::make_unique<Data::Draft>(
|
||||
_field,
|
||||
_header->getDraftMessageId(),
|
||||
key.topicRootId(),
|
||||
_preview->state()));
|
||||
std::make_unique<Data::Draft>(_field, id, _preview->state()));
|
||||
} else {
|
||||
_history->clearDraft(draftKeyCurrent());
|
||||
}
|
||||
|
@ -1757,7 +1760,7 @@ void ComposeControls::initKeyHandler() {
|
|||
}
|
||||
}
|
||||
_replyNextRequests.fire({
|
||||
.replyId = replyingToMessage(),
|
||||
.replyId = replyingToMessage().messageId,
|
||||
.direction = (isDown
|
||||
? ReplyNextRequest::Direction::Next
|
||||
: ReplyNextRequest::Direction::Previous)
|
||||
|
@ -2037,8 +2040,8 @@ Data::DraftKey ComposeControls::draftKey(DraftType type) const {
|
|||
case Section::History:
|
||||
case Section::Replies:
|
||||
return (type == DraftType::Edit)
|
||||
? Key::LocalEdit(_currentDialogsEntryState.rootId)
|
||||
: Key::Local(_currentDialogsEntryState.rootId);
|
||||
? Key::LocalEdit(_topicRootId)
|
||||
: Key::Local(_topicRootId);
|
||||
case Section::Scheduled:
|
||||
return (type == DraftType::Edit)
|
||||
? Key::ScheduledEdit()
|
||||
|
@ -2102,7 +2105,7 @@ void ComposeControls::registerDraftSource() {
|
|||
if (key != Data::DraftKey::None()) {
|
||||
const auto draft = [=] {
|
||||
return Storage::MessageDraft{
|
||||
_header->getDraftMessageId(),
|
||||
_header->getDraftReply(),
|
||||
_field->getTextWithTags(),
|
||||
_preview->state(),
|
||||
};
|
||||
|
@ -2150,8 +2153,8 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
|||
const auto draft = editDraft
|
||||
? editDraft
|
||||
: _history->draft(draftKey(DraftType::Normal));
|
||||
const auto editingId = (draft == editDraft)
|
||||
? FullMsgId{ _history->peer->id, draft ? draft->msgId : 0 }
|
||||
const auto editingId = (draft && draft == editDraft)
|
||||
? draft->reply.messageId
|
||||
: FullMsgId();
|
||||
|
||||
InvokeQueued(_autocomplete.get(), [=] { updateStickersByEmoji(); });
|
||||
|
@ -2232,7 +2235,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
|||
} else {
|
||||
_canReplaceMedia = false;
|
||||
_photoEditMedia = nullptr;
|
||||
_header->replyToMessage({ _history->peer->id, draft->msgId });
|
||||
_header->replyToMessage(draft->reply);
|
||||
if (_header->replyingToMessage()) {
|
||||
cancelForward();
|
||||
}
|
||||
|
@ -2241,9 +2244,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
|||
}
|
||||
|
||||
void ComposeControls::cancelForward() {
|
||||
_history->setForwardDraft(
|
||||
_currentDialogsEntryState.rootId,
|
||||
{});
|
||||
_history->setForwardDraft(_topicRootId, {});
|
||||
updateForwarding();
|
||||
}
|
||||
|
||||
|
@ -2840,8 +2841,7 @@ void ComposeControls::toggleTabbedSelectorMode() {
|
|||
&& !_regularWindow->adaptive().isOneColumn()) {
|
||||
Core::App().settings().setTabbedSelectorSectionEnabled(true);
|
||||
Core::App().saveSettingsDelayed();
|
||||
const auto topic = _history->peer->forumTopicFor(
|
||||
_currentDialogsEntryState.rootId);
|
||||
const auto topic = _history->peer->forumTopicFor(_topicRootId);
|
||||
pushTabbedSelectorToThirdSection(
|
||||
(topic ? topic : (Data::Thread*)_history),
|
||||
Window::SectionShow::Way::ClearStack);
|
||||
|
@ -2900,8 +2900,10 @@ void ComposeControls::editMessage(not_null<HistoryItem*> item) {
|
|||
key,
|
||||
std::make_unique<Data::Draft>(
|
||||
editData,
|
||||
item->id,
|
||||
key.topicRootId(),
|
||||
FullReplyTo{
|
||||
.messageId = item->fullId(),
|
||||
.topicRootId = key.topicRootId(),
|
||||
},
|
||||
cursor,
|
||||
previewState));
|
||||
applyDraft();
|
||||
|
@ -2968,25 +2970,26 @@ void ComposeControls::maybeCancelEditMessage() {
|
|||
}
|
||||
}
|
||||
|
||||
void ComposeControls::replyToMessage(FullMsgId id) {
|
||||
void ComposeControls::replyToMessage(FullReplyTo id) {
|
||||
Expects(_history != nullptr);
|
||||
Expects(draftKeyCurrent() != Data::DraftKey::None());
|
||||
|
||||
id.topicRootId = _topicRootId;
|
||||
if (!id) {
|
||||
cancelReplyMessage();
|
||||
return;
|
||||
}
|
||||
if (isEditingMessage()) {
|
||||
const auto key = draftKey(DraftType::Normal);
|
||||
Assert(key.topicRootId() == id.topicRootId);
|
||||
if (const auto localDraft = _history->draft(key)) {
|
||||
localDraft->msgId = id.msg;
|
||||
localDraft->reply = id;
|
||||
} else {
|
||||
_history->setDraft(
|
||||
key,
|
||||
std::make_unique<Data::Draft>(
|
||||
TextWithTags(),
|
||||
id.msg,
|
||||
key.topicRootId(),
|
||||
id,
|
||||
MessageCursor(),
|
||||
Data::PreviewState::Allowed));
|
||||
}
|
||||
|
@ -3008,11 +3011,11 @@ void ComposeControls::cancelReplyMessage() {
|
|||
if (_history) {
|
||||
const auto key = draftKey(DraftType::Normal);
|
||||
if (const auto localDraft = _history->draft(key)) {
|
||||
if (localDraft->msgId) {
|
||||
if (localDraft->reply.messageId) {
|
||||
if (localDraft->textWithTags.text.isEmpty()) {
|
||||
_history->clearDraft(key);
|
||||
} else {
|
||||
localDraft->msgId = 0;
|
||||
localDraft->reply = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3025,7 +3028,7 @@ void ComposeControls::cancelReplyMessage() {
|
|||
}
|
||||
|
||||
void ComposeControls::updateForwarding() {
|
||||
const auto rootId = _currentDialogsEntryState.rootId;
|
||||
const auto rootId = _topicRootId;
|
||||
const auto thread = (_history && rootId)
|
||||
? _history->peer->forumTopicFor(rootId)
|
||||
: (Data::Thread*)_history;
|
||||
|
@ -3118,7 +3121,7 @@ void ComposeControls::initForwardProcess() {
|
|||
) | rpl::start_with_next([=](const Data::EntryUpdate &update) {
|
||||
if (const auto topic = update.entry->asTopic()) {
|
||||
if (topic->history() == _history
|
||||
&& topic->rootId() == _currentDialogsEntryState.rootId) {
|
||||
&& topic->rootId() == _topicRootId) {
|
||||
updateForwarding();
|
||||
}
|
||||
}
|
||||
|
@ -3145,8 +3148,10 @@ bool ComposeControls::isEditingMessage() const {
|
|||
return _header->isEditingMessage();
|
||||
}
|
||||
|
||||
FullMsgId ComposeControls::replyingToMessage() const {
|
||||
return _header->replyingToMessage();
|
||||
FullReplyTo ComposeControls::replyingToMessage() const {
|
||||
auto result = _header->replyingToMessage();
|
||||
result.topicRootId = _topicRootId;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ComposeControls::readyToForward() const {
|
||||
|
|
|
@ -185,7 +185,7 @@ public:
|
|||
[[nodiscard]] bool isEditingMessage() const;
|
||||
[[nodiscard]] bool readyToForward() const;
|
||||
[[nodiscard]] const HistoryItemsList &forwardItems() const;
|
||||
[[nodiscard]] FullMsgId replyingToMessage() const;
|
||||
[[nodiscard]] FullReplyTo replyingToMessage() const;
|
||||
|
||||
[[nodiscard]] bool preventsClose(Fn<void()> &&continueCallback) const;
|
||||
|
||||
|
@ -198,7 +198,7 @@ public:
|
|||
void cancelEditMessage();
|
||||
void maybeCancelEditMessage(); // Confirm if changed and cancel.
|
||||
|
||||
void replyToMessage(FullMsgId id);
|
||||
void replyToMessage(FullReplyTo id);
|
||||
void cancelReplyMessage();
|
||||
|
||||
void updateForwarding();
|
||||
|
@ -345,6 +345,7 @@ private:
|
|||
rpl::event_stream<ChatHelpers::FileChosen> _stickerOrEmojiChosen;
|
||||
|
||||
History *_history = nullptr;
|
||||
MsgId _topicRootId = 0;
|
||||
Fn<bool()> _showSlowmodeError;
|
||||
Fn<Api::SendAction()> _sendActionFactory;
|
||||
rpl::variable<int> _slowmodeSecondsLeft;
|
||||
|
|
|
@ -117,7 +117,7 @@ void ForwardPanel::checkTexts() {
|
|||
: kNameNoCaptionsVersion;
|
||||
if (keepNames) {
|
||||
for (const auto item : _data.items) {
|
||||
if (const auto from = item->senderOriginal()) {
|
||||
if (const auto from = item->originalSender()) {
|
||||
version += from->nameVersion();
|
||||
} else if (const auto info = item->hiddenSenderInfo()) {
|
||||
++version;
|
||||
|
@ -154,7 +154,7 @@ void ForwardPanel::updateTexts() {
|
|||
auto names = std::vector<QString>();
|
||||
names.reserve(_data.items.size());
|
||||
for (const auto item : _data.items) {
|
||||
if (const auto from = item->senderOriginal()) {
|
||||
if (const auto from = item->originalSender()) {
|
||||
if (!insertedPeers.contains(from)) {
|
||||
insertedPeers.emplace(from);
|
||||
names.push_back(from->shortName());
|
||||
|
|
|
@ -655,7 +655,7 @@ BottomInfo::Data BottomInfoDataFromMessage(not_null<Message*> message) {
|
|||
}
|
||||
if (const auto msgsigned = item->Get<HistoryMessageSigned>()) {
|
||||
if (!msgsigned->isAnonymousRank) {
|
||||
result.author = msgsigned->author;
|
||||
result.author = msgsigned->postAuthor;
|
||||
}
|
||||
}
|
||||
if (message->displayedEditDate()) {
|
||||
|
|
|
@ -601,7 +601,7 @@ bool AddReplyToMessageAction(
|
|||
if (!item) {
|
||||
return;
|
||||
}
|
||||
list->replyToMessageRequestNotify(item->fullId());
|
||||
list->replyToMessageRequestNotify({ item->fullId() });
|
||||
}, &st::menuIconReply);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -68,10 +68,10 @@ Element *MousedElement/* = nullptr*/;
|
|||
HistoryMessageForwarded *prevForwarded,
|
||||
not_null<HistoryItem*> item,
|
||||
HistoryMessageForwarded *forwarded) {
|
||||
const auto sender = previous->senderOriginal();
|
||||
const auto sender = previous->originalSender();
|
||||
if ((prevForwarded != nullptr) != (forwarded != nullptr)) {
|
||||
return false;
|
||||
} else if (sender != item->senderOriginal()) {
|
||||
} else if (sender != item->originalSender()) {
|
||||
return false;
|
||||
} else if (!prevForwarded || sender) {
|
||||
return true;
|
||||
|
@ -178,7 +178,7 @@ bool DefaultElementDelegate::elementIsChatWide() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void DefaultElementDelegate::elementReplyTo(const FullMsgId &to) {
|
||||
void DefaultElementDelegate::elementReplyTo(const FullReplyTo &to) {
|
||||
}
|
||||
|
||||
void DefaultElementDelegate::elementStartInteraction(
|
||||
|
@ -275,8 +275,10 @@ QString DateTooltipText(not_null<Element*> view) {
|
|||
}
|
||||
if (view->isSignedAuthorElided()) {
|
||||
if (const auto msgsigned = item->Get<HistoryMessageSigned>()) {
|
||||
dateText += '\n'
|
||||
+ tr::lng_signed_author(tr::now, lt_user, msgsigned->author);
|
||||
dateText += '\n' + tr::lng_signed_author(
|
||||
tr::now,
|
||||
lt_user,
|
||||
msgsigned->postAuthor);
|
||||
}
|
||||
}
|
||||
return dateText;
|
||||
|
@ -1447,7 +1449,7 @@ void Element::unloadHeavyPart() {
|
|||
_heavyCustomEmoji = false;
|
||||
_text.unloadPersistentAnimation();
|
||||
if (const auto reply = data()->Get<HistoryMessageReply>()) {
|
||||
reply->replyToText.unloadPersistentAnimation();
|
||||
reply->unloadPersistentAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public:
|
|||
virtual void elementHandleViaClick(not_null<UserData*> bot) = 0;
|
||||
virtual bool elementIsChatWide() = 0;
|
||||
virtual not_null<Ui::PathShiftGradient*> elementPathShiftGradient() = 0;
|
||||
virtual void elementReplyTo(const FullMsgId &to) = 0;
|
||||
virtual void elementReplyTo(const FullReplyTo &to) = 0;
|
||||
virtual void elementStartInteraction(not_null<const Element*> view) = 0;
|
||||
virtual void elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
|
@ -149,7 +149,7 @@ public:
|
|||
const FullMsgId &context) override;
|
||||
void elementHandleViaClick(not_null<UserData*> bot) override;
|
||||
bool elementIsChatWide() override;
|
||||
void elementReplyTo(const FullMsgId &to) override;
|
||||
void elementReplyTo(const FullReplyTo &to) override;
|
||||
void elementStartInteraction(not_null<const Element*> view) override;
|
||||
void elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
|
|
|
@ -1735,7 +1735,7 @@ not_null<Ui::PathShiftGradient*> ListWidget::elementPathShiftGradient() {
|
|||
return _pathGradient.get();
|
||||
}
|
||||
|
||||
void ListWidget::elementReplyTo(const FullMsgId &to) {
|
||||
void ListWidget::elementReplyTo(const FullReplyTo &to) {
|
||||
replyToMessageRequestNotify(to);
|
||||
}
|
||||
|
||||
|
@ -2474,7 +2474,7 @@ void ListWidget::mouseDoubleClickEvent(QMouseEvent *e) {
|
|||
mouseActionCancel();
|
||||
switch (CurrentQuickAction()) {
|
||||
case DoubleClickQuickAction::Reply: {
|
||||
replyToMessageRequestNotify(_overElement->data()->fullId());
|
||||
replyToMessageRequestNotify({ _overElement->data()->fullId() });
|
||||
} break;
|
||||
case DoubleClickQuickAction::React: {
|
||||
toggleFavoriteReaction(_overElement);
|
||||
|
@ -3855,12 +3855,12 @@ bool ListWidget::lastMessageEditRequestNotify() const {
|
|||
}
|
||||
}
|
||||
|
||||
rpl::producer<FullMsgId> ListWidget::replyToMessageRequested() const {
|
||||
rpl::producer<FullReplyTo> ListWidget::replyToMessageRequested() const {
|
||||
return _requestedToReplyToMessage.events();
|
||||
}
|
||||
|
||||
void ListWidget::replyToMessageRequestNotify(FullMsgId item) {
|
||||
_requestedToReplyToMessage.fire(std::move(item));
|
||||
void ListWidget::replyToMessageRequestNotify(FullReplyTo id) {
|
||||
_requestedToReplyToMessage.fire(std::move(id));
|
||||
}
|
||||
|
||||
rpl::producer<FullMsgId> ListWidget::readMessageRequested() const {
|
||||
|
@ -3878,10 +3878,10 @@ void ListWidget::replyNextMessage(FullMsgId fullId, bool next) {
|
|||
if (!view->data()->isRegular()) {
|
||||
return replyNextMessage(newFullId, next);
|
||||
}
|
||||
replyToMessageRequestNotify(newFullId);
|
||||
replyToMessageRequestNotify({ newFullId });
|
||||
_requestedToShowMessage.fire_copy(newFullId);
|
||||
} else {
|
||||
replyToMessageRequestNotify(FullMsgId());
|
||||
replyToMessageRequestNotify({});
|
||||
_highlighter.clear();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -277,8 +277,8 @@ public:
|
|||
[[nodiscard]] rpl::producer<FullMsgId> editMessageRequested() const;
|
||||
void editMessageRequestNotify(FullMsgId item) const;
|
||||
[[nodiscard]] bool lastMessageEditRequestNotify() const;
|
||||
[[nodiscard]] rpl::producer<FullMsgId> replyToMessageRequested() const;
|
||||
void replyToMessageRequestNotify(FullMsgId item);
|
||||
[[nodiscard]] rpl::producer<FullReplyTo> replyToMessageRequested() const;
|
||||
void replyToMessageRequestNotify(FullReplyTo id);
|
||||
[[nodiscard]] rpl::producer<FullMsgId> readMessageRequested() const;
|
||||
[[nodiscard]] rpl::producer<FullMsgId> showMessageRequested() const;
|
||||
void replyNextMessage(FullMsgId fullId, bool next = true);
|
||||
|
@ -323,7 +323,7 @@ public:
|
|||
void elementHandleViaClick(not_null<UserData*> bot) override;
|
||||
bool elementIsChatWide() override;
|
||||
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
|
||||
void elementReplyTo(const FullMsgId &to) override;
|
||||
void elementReplyTo(const FullReplyTo &to) override;
|
||||
void elementStartInteraction(not_null<const Element*> view) override;
|
||||
void elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
|
@ -735,7 +735,7 @@ private:
|
|||
base::Timer _touchScrollTimer;
|
||||
|
||||
rpl::event_stream<FullMsgId> _requestedToEditMessage;
|
||||
rpl::event_stream<FullMsgId> _requestedToReplyToMessage;
|
||||
rpl::event_stream<FullReplyTo> _requestedToReplyToMessage;
|
||||
rpl::event_stream<FullMsgId> _requestedToReadMessage;
|
||||
rpl::event_stream<FullMsgId> _requestedToShowMessage;
|
||||
|
||||
|
|
|
@ -477,7 +477,7 @@ void Message::refreshRightBadge() {
|
|||
} else if (data()->author()->isMegagroup()) {
|
||||
if (const auto msgsigned = data()->Get<HistoryMessageSigned>()) {
|
||||
Assert(msgsigned->isAnonymousRank);
|
||||
return msgsigned->author;
|
||||
return msgsigned->postAuthor;
|
||||
}
|
||||
}
|
||||
const auto channel = data()->history()->peer->asMegagroup();
|
||||
|
@ -801,9 +801,9 @@ QSize Message::performCountOptimalSize() {
|
|||
accumulate_max(maxWidth, namew);
|
||||
}
|
||||
if (reply) {
|
||||
auto replyw = st::msgPadding.left() + reply->maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right();
|
||||
if (reply->replyToVia) {
|
||||
replyw += st::msgServiceFont->spacew + reply->replyToVia->maxWidth;
|
||||
auto replyw = st::msgPadding.left() + reply->maxWidth() - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right();
|
||||
if (reply->originalVia) {
|
||||
replyw += st::msgServiceFont->spacew + reply->originalVia->maxWidth;
|
||||
}
|
||||
accumulate_max(maxWidth, replyw);
|
||||
}
|
||||
|
@ -1736,8 +1736,8 @@ void Message::clickHandlerPressedChanged(
|
|||
toggleTopicButtonRipple(pressed);
|
||||
} else if (_viewButton) {
|
||||
_viewButton->checkLink(handler, pressed);
|
||||
} else if (const auto reply = displayedReply();
|
||||
reply && (handler == reply->replyToLink())) {
|
||||
} else if (const auto reply = displayedReply()
|
||||
; reply && (handler == reply->link())) {
|
||||
toggleReplyRipple(pressed);
|
||||
}
|
||||
}
|
||||
|
@ -2469,10 +2469,11 @@ bool Message::getStateReplyInfo(
|
|||
trect.y() + st::msgReplyPadding.top(),
|
||||
trect.width(),
|
||||
st::msgReplyBarSize.height());
|
||||
if ((reply->replyToMsg || reply->replyToStory)
|
||||
&& g.contains(point)) {
|
||||
outResult->link = reply->replyToLink();
|
||||
reply->ripple.lastPoint = point - g.topLeft();
|
||||
if (g.contains(point)) {
|
||||
if (const auto link = reply->link()) {
|
||||
outResult->link = reply->link();
|
||||
reply->ripple.lastPoint = point - g.topLeft();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -3439,7 +3440,7 @@ ClickHandlerPtr Message::fastReplyLink() const {
|
|||
}
|
||||
const auto itemId = data()->fullId();
|
||||
_fastReplyLink = std::make_shared<LambdaClickHandler>([=] {
|
||||
delegate()->elementReplyTo(itemId);
|
||||
delegate()->elementReplyTo({ itemId });
|
||||
});
|
||||
return _fastReplyLink;
|
||||
}
|
||||
|
|
|
@ -1002,7 +1002,7 @@ void RepliesWidget::sendingFilesConfirmed(
|
|||
album,
|
||||
action);
|
||||
}
|
||||
if (_composeControls->replyingToMessage().msg == action.replyTo.msgId) {
|
||||
if (_composeControls->replyingToMessage() == action.replyTo) {
|
||||
_composeControls->cancelReplyMessage();
|
||||
refreshTopBarActiveChat();
|
||||
}
|
||||
|
@ -1123,9 +1123,9 @@ bool RepliesWidget::showSendingFilesError(
|
|||
}
|
||||
|
||||
Api::SendAction RepliesWidget::prepareSendAction(
|
||||
Api::SendOptions options) const {
|
||||
Api::SendOptions options) const {
|
||||
auto result = Api::SendAction(_history, options);
|
||||
result.replyTo = { .msgId = replyToId(), .topicRootId = _rootId };
|
||||
result.replyTo = replyTo();
|
||||
result.options.sendAs = _composeControls->sendAsPeer();
|
||||
return result;
|
||||
}
|
||||
|
@ -1444,28 +1444,29 @@ SendMenu::Type RepliesWidget::sendMenuType() const {
|
|||
: SendMenu::Type::Scheduled;
|
||||
}
|
||||
|
||||
FullReplyTo RepliesWidget::replyTo() const {
|
||||
if (auto custom = _composeControls->replyingToMessage()) {
|
||||
custom.topicRootId = _rootId;
|
||||
return custom;
|
||||
}
|
||||
return FullReplyTo{
|
||||
.messageId = FullMsgId(_history->peer->id, _rootId),
|
||||
.topicRootId = _rootId,
|
||||
};
|
||||
}
|
||||
|
||||
void RepliesWidget::refreshTopBarActiveChat() {
|
||||
using namespace Dialogs;
|
||||
const auto state = EntryState{
|
||||
.key = (_topic ? Key{ _topic } : Key{ _history }),
|
||||
.section = EntryState::Section::Replies,
|
||||
.rootId = _rootId,
|
||||
.currentReplyToId = _composeControls->replyingToMessage().msg,
|
||||
.currentReplyTo = replyTo(),
|
||||
};
|
||||
_topBar->setActiveChat(state, _sendAction.get());
|
||||
_composeControls->setCurrentDialogsEntryState(state);
|
||||
controller()->setCurrentDialogsEntryState(state);
|
||||
}
|
||||
|
||||
MsgId RepliesWidget::replyToId() const {
|
||||
const auto custom = _composeControls->replyingToMessage().msg;
|
||||
return custom
|
||||
? custom
|
||||
: (_rootId == Data::ForumTopic::kGeneralId)
|
||||
? MsgId()
|
||||
: _rootId;
|
||||
}
|
||||
|
||||
void RepliesWidget::refreshUnreadCountBadge(std::optional<int> count) {
|
||||
if (count.has_value()) {
|
||||
_cornerButtons.updateJumpDownVisibility(count);
|
||||
|
@ -2052,8 +2053,8 @@ bool RepliesWidget::confirmSendingFiles(
|
|||
insertTextOnCancel);
|
||||
}
|
||||
|
||||
void RepliesWidget::replyToMessage(FullMsgId itemId) {
|
||||
_composeControls->replyToMessage(itemId);
|
||||
void RepliesWidget::replyToMessage(FullReplyTo id) {
|
||||
_composeControls->replyToMessage(std::move(id));
|
||||
refreshTopBarActiveChat();
|
||||
}
|
||||
|
||||
|
|
|
@ -243,7 +243,7 @@ private:
|
|||
mtpRequestId *const saveEditMsgRequestId);
|
||||
void chooseAttach(std::optional<bool> overrideSendImagesAsPhotos);
|
||||
[[nodiscard]] SendMenu::Type sendMenuType() const;
|
||||
[[nodiscard]] MsgId replyToId() const;
|
||||
[[nodiscard]] FullReplyTo replyTo() const;
|
||||
[[nodiscard]] HistoryItem *lookupRoot() const;
|
||||
[[nodiscard]] Data::ForumTopic *lookupTopic();
|
||||
[[nodiscard]] bool computeAreComments() const;
|
||||
|
@ -252,7 +252,7 @@ private:
|
|||
void pushReplyReturn(not_null<HistoryItem*> item);
|
||||
void checkReplyReturns();
|
||||
void recountChatWidth();
|
||||
void replyToMessage(FullMsgId itemId);
|
||||
void replyToMessage(FullReplyTo id);
|
||||
void refreshTopBarActiveChat();
|
||||
void refreshUnreadCountBadge(std::optional<int> count);
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ bool TranslateTracker::add(
|
|||
}
|
||||
if (!skipDependencies) {
|
||||
if (const auto reply = item->Get<HistoryMessageReply>()) {
|
||||
if (const auto to = reply->replyToMsg.get()) {
|
||||
if (const auto to = reply->resolvedMessage.get()) {
|
||||
add(to, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1069,7 +1069,7 @@ TextState Gif::textState(QPoint point, StateRequest request) const {
|
|||
if (reply) {
|
||||
const auto replyRect = QRect(rectx, recty, rectw, recth);
|
||||
if (replyRect.contains(point)) {
|
||||
result.link = reply->replyToLink();
|
||||
result.link = reply->link();
|
||||
reply->ripple.lastPoint = point - replyRect.topLeft();
|
||||
if (!reply->ripple.animation) {
|
||||
reply->ripple.animation = std::make_unique<Ui::RippleAnimation>(
|
||||
|
@ -1737,7 +1737,7 @@ int Gif::additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply
|
|||
accumulate_max(result, st::msgReplyPadding.left() + st::msgReplyPadding.left() + via->maxWidth + st::msgReplyPadding.left());
|
||||
}
|
||||
if (reply) {
|
||||
accumulate_max(result, st::msgReplyPadding.left() + reply->replyToWidth());
|
||||
accumulate_max(result, st::msgReplyPadding.left() + reply->maxWidth());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -464,7 +464,7 @@ TextState UnwrappedMedia::textState(QPoint point, StateRequest request) const {
|
|||
if (reply) {
|
||||
const auto replyRect = QRect(rectx, recty, rectw, recth);
|
||||
if (replyRect.contains(point)) {
|
||||
result.link = reply->replyToLink();
|
||||
result.link = reply->link();
|
||||
reply->ripple.lastPoint = point - replyRect.topLeft();
|
||||
if (!reply->ripple.animation) {
|
||||
reply->ripple.animation = std::make_unique<Ui::RippleAnimation>(
|
||||
|
@ -519,10 +519,9 @@ bool UnwrappedMedia::hasTextForCopy() const {
|
|||
return _content->hasTextForCopy();
|
||||
}
|
||||
|
||||
bool UnwrappedMedia::dragItemByHandler(
|
||||
const ClickHandlerPtr &p) const {
|
||||
bool UnwrappedMedia::dragItemByHandler(const ClickHandlerPtr &p) const {
|
||||
const auto reply = _parent->displayedReply();
|
||||
return !(reply && (reply->replyToLink() == p));
|
||||
return !reply || (reply->link() != p);
|
||||
}
|
||||
|
||||
QRect UnwrappedMedia::contentRectForReactions() const {
|
||||
|
@ -642,7 +641,7 @@ int UnwrappedMedia::additionalWidth(
|
|||
accumulate_max(result, 2 * st::msgReplyPadding.left() + via->maxWidth + st::msgReplyPadding.right());
|
||||
}
|
||||
if (reply) {
|
||||
accumulate_max(result, st::msgReplyPadding.left() + reply->replyToWidth());
|
||||
accumulate_max(result, st::msgReplyPadding.left() + reply->maxWidth());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -602,8 +602,7 @@ bool MainWidget::shareUrl(
|
|||
const auto topicRootId = thread->topicRootId();
|
||||
history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||
textWithTags,
|
||||
0, // replyTo
|
||||
topicRootId,
|
||||
FullReplyTo{ .topicRootId = topicRootId },
|
||||
cursor,
|
||||
Data::PreviewState::Allowed));
|
||||
history->clearLocalEditDraft(topicRootId);
|
||||
|
@ -746,8 +745,8 @@ void MainWidget::sendBotCommand(Bot::SendCommandRequest request) {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWidget::hideSingleUseKeyboard(PeerData *peer, MsgId replyTo) {
|
||||
_history->hideSingleUseKeyboard(peer, replyTo);
|
||||
void MainWidget::hideSingleUseKeyboard(FullMsgId replyToId) {
|
||||
_history->hideSingleUseKeyboard(replyToId);
|
||||
}
|
||||
|
||||
void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) {
|
||||
|
|
|
@ -188,7 +188,7 @@ public:
|
|||
not_null<const QMimeData*> data);
|
||||
|
||||
void sendBotCommand(Bot::SendCommandRequest request);
|
||||
void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo);
|
||||
void hideSingleUseKeyboard(FullMsgId replyToId);
|
||||
|
||||
void searchMessages(const QString &query, Dialogs::Key inChat);
|
||||
|
||||
|
|
|
@ -3037,7 +3037,7 @@ void OverlayWidget::refreshMediaViewer() {
|
|||
|
||||
void OverlayWidget::refreshFromLabel() {
|
||||
if (_message) {
|
||||
_from = _message->senderOriginal();
|
||||
_from = _message->originalSender();
|
||||
if (const auto info = _message->hiddenSenderInfo()) {
|
||||
_fromName = info->name;
|
||||
} else {
|
||||
|
|
|
@ -59,6 +59,7 @@ constexpr auto kMultiDraftTagOld = quint64(0xFFFF'FFFF'FFFF'FF01ULL);
|
|||
constexpr auto kMultiDraftCursorsTagOld = quint64(0xFFFF'FFFF'FFFF'FF02ULL);
|
||||
constexpr auto kMultiDraftTag = quint64(0xFFFF'FFFF'FFFF'FF03ULL);
|
||||
constexpr auto kMultiDraftCursorsTag = quint64(0xFFFF'FFFF'FFFF'FF04ULL);
|
||||
constexpr auto kRichDraftsTag = quint64(0xFFFF'FFFF'FFFF'FF05ULL);
|
||||
|
||||
enum { // Local Storage Keys
|
||||
lskUserMap = 0x00,
|
||||
|
@ -1041,7 +1042,7 @@ void EnumerateDrafts(
|
|||
}
|
||||
callback(
|
||||
key,
|
||||
draft->msgId,
|
||||
draft->reply,
|
||||
draft->textWithTags,
|
||||
draft->previewState,
|
||||
draft->cursor);
|
||||
|
@ -1049,12 +1050,12 @@ void EnumerateDrafts(
|
|||
for (const auto &[key, source] : sources) {
|
||||
const auto draft = source.draft();
|
||||
const auto cursor = source.cursor();
|
||||
if (draft.msgId
|
||||
if (draft.reply.messageId
|
||||
|| !draft.textWithTags.text.isEmpty()
|
||||
|| cursor != MessageCursor()) {
|
||||
callback(
|
||||
key,
|
||||
draft.msgId,
|
||||
draft.reply,
|
||||
draft.textWithTags,
|
||||
draft.previewState,
|
||||
cursor);
|
||||
|
@ -1119,14 +1120,18 @@ void Account::writeDrafts(not_null<History*> history) {
|
|||
auto size = int(sizeof(quint64) * 2 + sizeof(quint32));
|
||||
const auto sizeCallback = [&](
|
||||
auto&&, // key
|
||||
MsgId, // msgId
|
||||
const FullReplyTo &reply,
|
||||
const TextWithTags &text,
|
||||
Data::PreviewState,
|
||||
auto&&) { // cursor
|
||||
size += sizeof(qint64) // key
|
||||
+ Serialize::stringSize(text.text)
|
||||
+ sizeof(qint64) + TextUtilities::SerializeTagsSize(text.tags)
|
||||
+ sizeof(qint64) + sizeof(qint32); // msgId, previewState
|
||||
+ sizeof(qint64) + sizeof(qint64) // messageId
|
||||
+ Serialize::stringSize(reply.quote.text)
|
||||
+ sizeof(qint64)
|
||||
+ TextUtilities::SerializeTagsSize(reply.quote.tags)
|
||||
+ sizeof(qint32); // previewState
|
||||
};
|
||||
EnumerateDrafts(
|
||||
map,
|
||||
|
@ -1136,13 +1141,13 @@ void Account::writeDrafts(not_null<History*> history) {
|
|||
|
||||
EncryptedDescriptor data(size);
|
||||
data.stream
|
||||
<< quint64(kMultiDraftTag)
|
||||
<< quint64(kRichDraftsTag)
|
||||
<< SerializePeerId(peerId)
|
||||
<< quint32(count);
|
||||
|
||||
const auto writeCallback = [&](
|
||||
const Data::DraftKey &key,
|
||||
MsgId msgId,
|
||||
const FullReplyTo &reply,
|
||||
const TextWithTags &text,
|
||||
Data::PreviewState previewState,
|
||||
auto&&) { // cursor
|
||||
|
@ -1150,7 +1155,10 @@ void Account::writeDrafts(not_null<History*> history) {
|
|||
<< key.serialize()
|
||||
<< text.text
|
||||
<< TextUtilities::SerializeTags(text.tags)
|
||||
<< qint64(msgId.bare)
|
||||
<< qint64(reply.messageId.peer.value)
|
||||
<< qint64(reply.messageId.msg.bare)
|
||||
<< reply.quote.text
|
||||
<< TextUtilities::SerializeTags(reply.quote.tags)
|
||||
<< qint32(previewState);
|
||||
};
|
||||
EnumerateDrafts(
|
||||
|
@ -1201,7 +1209,7 @@ void Account::writeDraftCursors(not_null<History*> history) {
|
|||
|
||||
const auto writeCallback = [&](
|
||||
const Data::DraftKey &key,
|
||||
MsgId, // msgId
|
||||
auto&&, // reply
|
||||
auto&&, // text
|
||||
Data::PreviewState,
|
||||
const MessageCursor &cursor) { // cursor
|
||||
|
@ -1343,7 +1351,9 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
|
|||
|
||||
quint64 tag = 0;
|
||||
draft.stream >> tag;
|
||||
if (tag != kMultiDraftTag && tag != kMultiDraftTagOld) {
|
||||
if (tag != kRichDraftsTag
|
||||
&& tag != kMultiDraftTag
|
||||
&& tag != kMultiDraftTagOld) {
|
||||
readDraftsWithCursorsLegacy(history, draft, tag);
|
||||
return;
|
||||
}
|
||||
|
@ -1359,24 +1369,43 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
|
|||
}
|
||||
auto map = Data::HistoryDrafts();
|
||||
const auto keysOld = (tag == kMultiDraftTagOld);
|
||||
const auto rich = (tag == kRichDraftsTag);
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
TextWithTags data;
|
||||
QByteArray tagsSerialized;
|
||||
qint64 keyValue = 0, messageId = 0;
|
||||
TextWithTags quote;
|
||||
TextWithTags text;
|
||||
QByteArray textTagsSerialized;
|
||||
QByteArray quoteTagsSerialized;
|
||||
qint64 keyValue = 0;
|
||||
qint64 messageIdPeer = 0, messageIdMsg = 0;
|
||||
qint32 keyValueOld = 0, uncheckedPreviewState = 0;
|
||||
if (keysOld) {
|
||||
draft.stream >> keyValueOld;
|
||||
} else {
|
||||
draft.stream >> keyValue;
|
||||
}
|
||||
draft.stream
|
||||
>> data.text
|
||||
>> tagsSerialized
|
||||
>> messageId
|
||||
>> uncheckedPreviewState;
|
||||
data.tags = TextUtilities::DeserializeTags(
|
||||
tagsSerialized,
|
||||
data.text.size());
|
||||
if (!rich) {
|
||||
draft.stream
|
||||
>> text.text
|
||||
>> textTagsSerialized
|
||||
>> messageIdMsg
|
||||
>> uncheckedPreviewState;
|
||||
messageIdPeer = peerId.value;
|
||||
} else {
|
||||
draft.stream
|
||||
>> text.text
|
||||
>> textTagsSerialized
|
||||
>> messageIdPeer
|
||||
>> messageIdMsg
|
||||
>> quote.text
|
||||
>> quoteTagsSerialized
|
||||
>> uncheckedPreviewState;
|
||||
quote.tags = TextUtilities::DeserializeTags(
|
||||
quoteTagsSerialized,
|
||||
quote.text.size());
|
||||
}
|
||||
text.tags = TextUtilities::DeserializeTags(
|
||||
textTagsSerialized,
|
||||
text.text.size());
|
||||
auto previewState = Data::PreviewState::Allowed;
|
||||
switch (static_cast<Data::PreviewState>(uncheckedPreviewState)) {
|
||||
case Data::PreviewState::Cancelled:
|
||||
|
@ -1388,9 +1417,14 @@ void Account::readDraftsWithCursors(not_null<History*> history) {
|
|||
: Data::DraftKey::FromSerialized(keyValue);
|
||||
if (key && !key.isCloud()) {
|
||||
map.emplace(key, std::make_unique<Data::Draft>(
|
||||
data,
|
||||
messageId,
|
||||
key.topicRootId(),
|
||||
text,
|
||||
FullReplyTo{
|
||||
.messageId = FullMsgId(
|
||||
PeerId(messageIdPeer),
|
||||
MsgId(messageIdMsg)),
|
||||
.quote = quote,
|
||||
.topicRootId = key.topicRootId(),
|
||||
},
|
||||
MessageCursor(),
|
||||
previewState));
|
||||
}
|
||||
|
@ -1455,8 +1489,7 @@ void Account::readDraftsWithCursorsLegacy(
|
|||
Data::DraftKey::Local(topicRootId),
|
||||
std::make_unique<Data::Draft>(
|
||||
msgData,
|
||||
msgReplyTo,
|
||||
topicRootId,
|
||||
FullReplyTo{ FullMsgId(peerId, MsgId(msgReplyTo)) },
|
||||
MessageCursor(),
|
||||
(msgPreviewCancelled
|
||||
? Data::PreviewState::Cancelled
|
||||
|
@ -1467,8 +1500,7 @@ void Account::readDraftsWithCursorsLegacy(
|
|||
Data::DraftKey::LocalEdit(topicRootId),
|
||||
std::make_unique<Data::Draft>(
|
||||
editData,
|
||||
editMsgId,
|
||||
topicRootId,
|
||||
FullReplyTo{ FullMsgId(peerId, editMsgId) },
|
||||
MessageCursor(),
|
||||
(editPreviewCancelled
|
||||
? Data::PreviewState::Cancelled
|
||||
|
|
|
@ -51,7 +51,7 @@ using FileKey = quint64;
|
|||
enum class StartResult : uchar;
|
||||
|
||||
struct MessageDraft {
|
||||
MsgId msgId = 0;
|
||||
FullReplyTo reply;
|
||||
TextWithTags textWithTags;
|
||||
Data::PreviewState previewState = Data::PreviewState::Allowed;
|
||||
};
|
||||
|
|
|
@ -159,8 +159,7 @@ Data::Draft OccupiedDraft(const QString &normalizedName) {
|
|||
+ QString::number(OccupationTag())
|
||||
+ ";n:"
|
||||
+ normalizedName },
|
||||
MsgId(0), // replyTo
|
||||
kTopicRootId,
|
||||
FullReplyTo(),
|
||||
MessageCursor(),
|
||||
Data::PreviewState::Allowed
|
||||
};
|
||||
|
|
|
@ -1060,12 +1060,14 @@ void Manager::notificationActivated(
|
|||
const auto replyToId = (id.msgId > 0
|
||||
&& !history->peer->isUser()
|
||||
&& id.msgId != topicRootId)
|
||||
? id.msgId
|
||||
: 0;
|
||||
? FullMsgId(history->peer->id, id.msgId)
|
||||
: FullMsgId();
|
||||
auto draft = std::make_unique<Data::Draft>(
|
||||
reply,
|
||||
replyToId,
|
||||
topicRootId,
|
||||
FullReplyTo{
|
||||
.messageId = replyToId,
|
||||
.topicRootId = topicRootId,
|
||||
},
|
||||
MessageCursor{
|
||||
int(reply.text.size()),
|
||||
int(reply.text.size()),
|
||||
|
@ -1150,7 +1152,7 @@ void Manager::notificationReplied(
|
|||
? topicRootId
|
||||
: MsgId(0);
|
||||
message.action.replyTo = {
|
||||
.msgId = replyToId,
|
||||
.messageId = { replyToId ? history->peer->id : 0, replyToId },
|
||||
.topicRootId = topic ? topic->rootId() : 0,
|
||||
};
|
||||
message.action.clearDraft = false;
|
||||
|
|
|
@ -112,7 +112,10 @@ void ShareBotGame(
|
|||
}
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
FullReplyTo{ .msgId = replyTo, .topicRootId = topicRootId },
|
||||
FullReplyTo{
|
||||
.messageId = { replyTo ? history->peer->id : 0, replyTo },
|
||||
.topicRootId = topicRootId,
|
||||
},
|
||||
randomId,
|
||||
Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
|
||||
MTP_flags(flags),
|
||||
|
@ -1036,16 +1039,12 @@ void Filler::addCreatePoll() {
|
|||
? SendMenu::Type::SilentOnly
|
||||
: SendMenu::Type::Scheduled;
|
||||
const auto flag = PollData::Flags();
|
||||
const auto topicRootId = _request.rootId;
|
||||
const auto replyToId = _request.currentReplyToId
|
||||
? _request.currentReplyToId
|
||||
: topicRootId;
|
||||
const auto replyTo = _request.currentReplyTo;
|
||||
auto callback = [=] {
|
||||
PeerMenuCreatePoll(
|
||||
controller,
|
||||
peer,
|
||||
replyToId,
|
||||
topicRootId,
|
||||
replyTo,
|
||||
flag,
|
||||
flag,
|
||||
source,
|
||||
|
@ -1464,8 +1463,7 @@ void PeerMenuShareContactBox(
|
|||
void PeerMenuCreatePoll(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
MsgId replyToId,
|
||||
MsgId topicRootId,
|
||||
FullReplyTo replyTo,
|
||||
PollData::Flags chosen,
|
||||
PollData::Flags disabled,
|
||||
Api::SendType sendType,
|
||||
|
@ -1490,10 +1488,12 @@ void PeerMenuCreatePoll(
|
|||
auto action = Api::SendAction(
|
||||
peer->owner().history(peer),
|
||||
result.options);
|
||||
action.clearDraft = false;
|
||||
action.replyTo = { .msgId = replyToId, .topicRootId = topicRootId };
|
||||
action.replyTo = replyTo;
|
||||
const auto topicRootId = replyTo.topicRootId;
|
||||
if (const auto local = action.history->localDraft(topicRootId)) {
|
||||
action.clearDraft = local->textWithTags.text.isEmpty();
|
||||
} else {
|
||||
action.clearDraft = false;
|
||||
}
|
||||
const auto api = &peer->session().api();
|
||||
api->polls().create(result.poll, action, crl::guard(weak, [=] {
|
||||
|
@ -1637,7 +1637,7 @@ void BlockSenderFromRepliesBox(
|
|||
PeerMenuBlockUserBox(
|
||||
box,
|
||||
&controller->window(),
|
||||
item->senderOriginal(),
|
||||
item->originalSender(),
|
||||
true,
|
||||
Window::ClearReply{ id });
|
||||
}
|
||||
|
|
|
@ -86,8 +86,7 @@ void PeerMenuAddChannelMembers(
|
|||
void PeerMenuCreatePoll(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer,
|
||||
MsgId replyToId = 0,
|
||||
MsgId topicRootId = 0,
|
||||
FullReplyTo replyTo = FullReplyTo(),
|
||||
PollData::Flags chosen = PollData::Flags(),
|
||||
PollData::Flags disabled = PollData::Flags(),
|
||||
Api::SendType sendType = Api::SendType::Normal,
|
||||
|
|
|
@ -1526,8 +1526,7 @@ bool SessionController::switchInlineQuery(
|
|||
};
|
||||
auto draft = std::make_unique<Data::Draft>(
|
||||
textWithTags,
|
||||
to.currentReplyToId,
|
||||
to.rootId,
|
||||
to.currentReplyTo,
|
||||
cursor,
|
||||
Data::PreviewState::Allowed);
|
||||
|
||||
|
@ -1539,11 +1538,12 @@ bool SessionController::switchInlineQuery(
|
|||
std::make_shared<HistoryView::ScheduledMemento>(history),
|
||||
params);
|
||||
} else {
|
||||
const auto topicRootId = to.currentReplyTo.topicRootId;
|
||||
history->setLocalDraft(std::move(draft));
|
||||
history->clearLocalEditDraft(to.rootId);
|
||||
history->clearLocalEditDraft(topicRootId);
|
||||
if (to.section == Section::Replies) {
|
||||
const auto commentId = MsgId();
|
||||
showRepliesForMessage(history, to.rootId, commentId, params);
|
||||
showRepliesForMessage(history, topicRootId, commentId, params);
|
||||
} else {
|
||||
showPeerHistory(history->peer, params);
|
||||
}
|
||||
|
@ -1560,7 +1560,7 @@ bool SessionController::switchInlineQuery(
|
|||
.section = (thread->asTopic()
|
||||
? Dialogs::EntryState::Section::Replies
|
||||
: Dialogs::EntryState::Section::History),
|
||||
.rootId = thread->topicRootId(),
|
||||
.currentReplyTo = { .topicRootId = thread->topicRootId() },
|
||||
};
|
||||
return switchInlineQuery(entryState, bot, query);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue