Implement sending of shortcutted messages.

This commit is contained in:
John Preston 2024-02-26 22:24:00 +04:00
parent 5c11fa4f63
commit 7f3ebde252
35 changed files with 709 additions and 934 deletions

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_media.h" #include "api/api_media.h"
#include "api/api_text_entities.h" #include "api/api_text_entities.h"
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "data/business/data_shortcut_messages.h"
#include "data/data_histories.h" #include "data/data_histories.h"
#include "data/data_scheduled_messages.h" #include "data/data_scheduled_messages.h"
#include "data/data_session.h" #include "data/data_session.h"
@ -92,6 +93,8 @@ mtpRequestId EditMessage(
const auto id = item->isScheduled() const auto id = item->isScheduled()
? session->data().scheduledMessages().lookupId(item) ? session->data().scheduledMessages().lookupId(item)
: item->isBusinessShortcut()
? session->data().shortcutMessages().lookupId(item)
: item->id; : item->id;
return api->request(MTPmessages_EditMessage( return api->request(MTPmessages_EditMessage(
MTP_flags(flags), MTP_flags(flags),

View file

@ -85,20 +85,21 @@ void SendExistingMedia(
? (*localMessageId) ? (*localMessageId)
: session->data().nextLocalMessageId()); : session->data().nextLocalMessageId());
const auto randomId = base::RandomValue<uint64>(); const auto randomId = base::RandomValue<uint64>();
const auto &action = message.action;
auto flags = NewMessageFlags(peer); auto flags = NewMessageFlags(peer);
auto sendFlags = MTPmessages_SendMedia::Flags(0); auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (message.action.replyTo) { if (action.replyTo) {
flags |= MessageFlag::HasReplyInfo; flags |= MessageFlag::HasReplyInfo;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to; sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
} }
const auto anonymousPost = peer->amAnonymous(); const auto anonymousPost = peer->amAnonymous();
const auto silentPost = ShouldSendSilent(peer, message.action.options); const auto silentPost = ShouldSendSilent(peer, action.options);
InnerFillMessagePostFlags(message.action.options, peer, flags); InnerFillMessagePostFlags(action.options, peer, flags);
if (silentPost) { if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent; sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
} }
const auto sendAs = message.action.options.sendAs; const auto sendAs = action.options.sendAs;
const auto messageFromId = sendAs const auto messageFromId = sendAs
? sendAs->id ? sendAs->id
: anonymousPost : anonymousPost
@ -125,33 +126,30 @@ void SendExistingMedia(
} }
const auto captionText = caption.text; const auto captionText = caption.text;
if (message.action.options.scheduled) { if (action.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled; flags |= MessageFlag::IsOrWasScheduled;
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date; sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
} }
if (message.action.options.shortcutId) { if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut; sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
} }
session->data().registerMessageRandomId(randomId, newId); session->data().registerMessageRandomId(randomId, newId);
const auto viaBotId = UserId(); history->addNewLocalMessage({
history->addNewLocalMessage( .id = newId.msg,
newId.msg, .flags = flags,
flags, .from = messageFromId,
viaBotId, .replyTo = action.replyTo,
message.action.replyTo, .date = HistoryItem::NewMessageDate(action.options),
HistoryItem::NewMessageDate(message.action.options.scheduled), .shortcutId = action.options.shortcutId,
messageFromId, .postAuthor = messagePostAuthor,
messagePostAuthor, }, media, caption);
media,
caption,
HistoryMessageMarkupData());
const auto performRequest = [=](const auto &repeatRequest) -> void { const auto performRequest = [=](const auto &repeatRequest) -> void {
auto &histories = history->owner().histories(); auto &histories = history->owner().histories();
const auto session = &history->session(); const auto session = &history->session();
const auto &action = message.action;
const auto usedFileReference = media->fileReference(); const auto usedFileReference = media->fileReference();
histories.sendPreparedMessage( histories.sendPreparedMessage(
history, history,
@ -187,7 +185,7 @@ void SendExistingMedia(
}; };
performRequest(performRequest); performRequest(performRequest);
api->finishForwarding(message.action); api->finishForwarding(action);
} }
} // namespace } // namespace
@ -307,23 +305,23 @@ bool SendDice(MessageToSend &message) {
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date; sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
} }
if (action.options.shortcutId) { if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut; sendFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
} }
session->data().registerMessageRandomId(randomId, newId); session->data().registerMessageRandomId(randomId, newId);
const auto viaBotId = UserId(); history->addNewLocalMessage({
history->addNewLocalMessage( .id = newId.msg,
newId.msg, .flags = flags,
flags, .from = messageFromId,
viaBotId, .replyTo = action.replyTo,
action.replyTo, .date = HistoryItem::NewMessageDate(action.options),
HistoryItem::NewMessageDate(action.options.scheduled), .shortcutId = action.options.shortcutId,
messageFromId, .postAuthor = messagePostAuthor,
messagePostAuthor, }, TextWithEntities(), MTP_messageMediaDice(
TextWithEntities(), MTP_int(0),
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)), MTP_string(emoji)));
HistoryMessageMarkupData());
histories.sendPreparedMessage( histories.sendPreparedMessage(
history, history,
action.replyTo, action.replyTo,
@ -420,7 +418,13 @@ void SendConfirmedFile(
if (file->to.options.scheduled) { if (file->to.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled; flags |= MessageFlag::IsOrWasScheduled;
// Scheduled messages have no the 'edited' badge. // Scheduled messages have no 'edited' badge.
flags |= MessageFlag::HideEdited;
}
if (file->to.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
// Shortcut messages have no 'edited' badge.
flags |= MessageFlag::HideEdited; flags |= MessageFlag::HideEdited;
} }
if (file->type == SendMediaType::Audio) { if (file->type == SendMediaType::Audio) {
@ -429,8 +433,7 @@ void SendConfirmedFile(
} }
} }
const auto messageFromId = const auto messageFromId = file->to.options.sendAs
file->to.options.sendAs
? file->to.options.sendAs->id ? file->to.options.sendAs->id
: anonymousPost : anonymousPost
? PeerId() ? PeerId()
@ -500,19 +503,15 @@ void SendConfirmedFile(
edition.savePreviousMedia = true; edition.savePreviousMedia = true;
itemToEdit->applyEdition(std::move(edition)); itemToEdit->applyEdition(std::move(edition));
} else { } else {
const auto viaBotId = UserId(); history->addNewLocalMessage({
history->addNewLocalMessage( .id = newId.msg,
newId.msg, .flags = flags,
flags, .from = messageFromId,
viaBotId, .replyTo = file->to.replyTo,
file->to.replyTo, .date = HistoryItem::NewMessageDate(file->to.options),
HistoryItem::NewMessageDate(file->to.options.scheduled), .shortcutId = file->to.options.shortcutId,
messageFromId, .postAuthor = messagePostAuthor,
messagePostAuthor, }, caption, media);
caption,
media,
HistoryMessageMarkupData(),
groupId);
} }
if (isEditing) { if (isEditing) {

View file

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/mtp_instance.h" #include "mtproto/mtp_instance.h"
#include "mtproto/mtproto_config.h" #include "mtproto/mtproto_config.h"
#include "mtproto/mtproto_dc_options.h" #include "mtproto/mtproto_dc_options.h"
#include "data/business/data_shortcut_messages.h"
#include "data/notify/data_notify_settings.h" #include "data/notify/data_notify_settings.h"
#include "data/stickers/data_stickers.h" #include "data/stickers/data_stickers.h"
#include "data/data_saved_messages.h" #include "data/data_saved_messages.h"
@ -1774,6 +1775,31 @@ void Updates::feedUpdate(const MTPUpdate &update) {
session().data().scheduledMessages().apply(d); session().data().scheduledMessages().apply(d);
} break; } break;
case mtpc_updateQuickReplies: {
const auto &d = update.c_updateQuickReplies();
session().data().shortcutMessages().apply(d);
} break;
case mtpc_updateNewQuickReply: {
const auto &d = update.c_updateNewQuickReply();
session().data().shortcutMessages().apply(d);
} break;
case mtpc_updateDeleteQuickReply: {
const auto &d = update.c_updateDeleteQuickReply();
session().data().shortcutMessages().apply(d);
} break;
case mtpc_updateQuickReplyMessage: {
const auto &d = update.c_updateQuickReplyMessage();
session().data().shortcutMessages().apply(d);
} break;
case mtpc_updateDeleteQuickReplyMessages: {
const auto &d = update.c_updateDeleteQuickReplyMessages();
session().data().shortcutMessages().apply(d);
} break;
case mtpc_updateWebPage: { case mtpc_updateWebPage: {
auto &d = update.c_updateWebPage(); auto &d = update.c_updateWebPage();

View file

@ -2449,6 +2449,14 @@ void ApiWrap::refreshFileReference(
request(MTPmessages_GetScheduledMessages( request(MTPmessages_GetScheduledMessages(
item->history()->peer->input, item->history()->peer->input,
MTP_vector<MTPint>(1, MTP_int(realId)))); MTP_vector<MTPint>(1, MTP_int(realId))));
} else if (item->isBusinessShortcut()) {
const auto &shortcuts = _session->data().shortcutMessages();
const auto realId = shortcuts.lookupId(item);
request(MTPmessages_GetQuickReplyMessages(
MTP_flags(MTPmessages_GetQuickReplyMessages::Flag::f_id),
MTP_int(item->shortcutId()),
MTP_vector<MTPint>(1, MTP_int(realId)),
MTP_long(0)));
} else if (const auto channel = item->history()->peer->asChannel()) { } else if (const auto channel = item->history()->peer->asChannel()) {
request(MTPchannels_GetMessages( request(MTPchannels_GetMessages(
channel->inputChannel, channel->inputChannel,
@ -3232,6 +3240,7 @@ void ApiWrap::forwardMessages(
sendFlags |= SendFlag::f_schedule_date; sendFlags |= SendFlag::f_schedule_date;
} }
if (action.options.shortcutId) { if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= SendFlag::f_quick_reply_shortcut; sendFlags |= SendFlag::f_quick_reply_shortcut;
} }
if (draft.options != Data::ForwardOptions::PreserveInfo) { if (draft.options != Data::ForwardOptions::PreserveInfo) {
@ -3317,14 +3326,15 @@ void ApiWrap::forwardMessages(
const auto messagePostAuthor = peer->isBroadcast() const auto messagePostAuthor = peer->isBroadcast()
? self->name() ? self->name()
: QString(); : QString();
history->addNewLocalMessage( history->addNewLocalMessage({
newId.msg, .id = newId.msg,
flags, .flags = flags,
HistoryItem::NewMessageDate(action.options.scheduled), .from = messageFromId,
messageFromId, .replyTo = { .topicRootId = topMsgId },
messagePostAuthor, .date = HistoryItem::NewMessageDate(action.options),
item, .shortcutId = action.options.shortcutId,
topMsgId); .postAuthor = messagePostAuthor,
}, item);
_session->data().registerMessageRandomId(randomId, newId); _session->data().registerMessageRandomId(randomId, newId);
if (!localIds) { if (!localIds) {
localIds = std::make_shared<base::flat_map<uint64, FullMsgId>>(); localIds = std::make_shared<base::flat_map<uint64, FullMsgId>>();
@ -3405,6 +3415,9 @@ void ApiWrap::sendSharedContact(
if (action.options.scheduled) { if (action.options.scheduled) {
flags |= MessageFlag::IsOrWasScheduled; flags |= MessageFlag::IsOrWasScheduled;
} }
if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
}
const auto messageFromId = action.options.sendAs const auto messageFromId = action.options.sendAs
? action.options.sendAs->id ? action.options.sendAs->id
: anonymousPost : anonymousPost
@ -3413,23 +3426,20 @@ void ApiWrap::sendSharedContact(
const auto messagePostAuthor = peer->isBroadcast() const auto messagePostAuthor = peer->isBroadcast()
? _session->user()->name() ? _session->user()->name()
: QString(); : QString();
const auto viaBotId = UserId(); const auto item = history->addNewLocalMessage({
const auto item = history->addNewLocalMessage( .id = newId.msg,
newId.msg, .flags = flags,
flags, .from = messageFromId,
viaBotId, .replyTo = action.replyTo,
action.replyTo, .date = HistoryItem::NewMessageDate(action.options),
HistoryItem::NewMessageDate(action.options.scheduled), .shortcutId = action.options.shortcutId,
messageFromId, .postAuthor = messagePostAuthor,
messagePostAuthor, }, TextWithEntities(), MTP_messageMediaContact(
TextWithEntities(), MTP_string(phone),
MTP_messageMediaContact( MTP_string(firstName),
MTP_string(phone), MTP_string(lastName),
MTP_string(firstName), MTP_string(), // vcard
MTP_string(lastName), MTP_long(userId.bare)));
MTP_string(), // vcard
MTP_long(userId.bare)),
HistoryMessageMarkupData());
const auto media = MTP_inputMediaContact( const auto media = MTP_inputMediaContact(
MTP_string(phone), MTP_string(phone),
@ -3737,21 +3747,19 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
mediaFlags |= MTPmessages_SendMedia::Flag::f_schedule_date; mediaFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
} }
if (action.options.shortcutId) { if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= MTPmessages_SendMessage::Flag::f_quick_reply_shortcut; sendFlags |= MTPmessages_SendMessage::Flag::f_quick_reply_shortcut;
mediaFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut; mediaFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
} }
const auto viaBotId = UserId(); lastMessage = history->addNewLocalMessage({
lastMessage = history->addNewLocalMessage( .id = newId.msg,
newId.msg, .flags = flags,
flags, .from = messageFromId,
viaBotId, .replyTo = action.replyTo,
action.replyTo, .date = HistoryItem::NewMessageDate(action.options),
HistoryItem::NewMessageDate(action.options.scheduled), .shortcutId = action.options.shortcutId,
messageFromId, .postAuthor = messagePostAuthor,
messagePostAuthor, }, sending, media);
sending,
media,
HistoryMessageMarkupData());
const auto done = [=]( const auto done = [=](
const MTPUpdates &result, const MTPUpdates &result,
const MTP::Response &response) { const MTP::Response &response) {
@ -3903,6 +3911,7 @@ void ApiWrap::sendInlineResult(
sendFlags |= SendFlag::f_schedule_date; sendFlags |= SendFlag::f_schedule_date;
} }
if (action.options.shortcutId) { if (action.options.shortcutId) {
flags |= MessageFlag::ShortcutMessage;
sendFlags |= SendFlag::f_quick_reply_shortcut; sendFlags |= SendFlag::f_quick_reply_shortcut;
} }
if (action.options.hideViaBot) { if (action.options.hideViaBot) {
@ -3923,15 +3932,18 @@ void ApiWrap::sendInlineResult(
_session->data().registerMessageRandomId(randomId, newId); _session->data().registerMessageRandomId(randomId, newId);
data->addToHistory( data->addToHistory(history, {
history, .id = newId.msg,
flags, .flags = flags,
newId.msg, .from = messageFromId,
messageFromId, .replyTo = action.replyTo,
HistoryItem::NewMessageDate(action.options.scheduled), .date = HistoryItem::NewMessageDate(action.options),
(bot && !action.options.hideViaBot) ? peerToUser(bot->id) : 0, .shortcutId = action.options.shortcutId,
action.replyTo, .viaBotId = ((bot && !action.options.hideViaBot)
messagePostAuthor); ? peerToUser(bot->id)
: UserId()),
.postAuthor = messagePostAuthor,
});
history->clearCloudDraft(topicRootId); history->clearCloudDraft(topicRootId);
history->startSavingCloudDraft(topicRootId); history->startSavingCloudDraft(topicRootId);

View file

@ -81,11 +81,11 @@ constexpr auto kMaxWallPaperSlugLength = 255;
const auto flags = MessageFlag::FakeHistoryItem const auto flags = MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId | MessageFlag::HasFromId
| (out ? MessageFlag::Outgoing : MessageFlag(0)); | (out ? MessageFlag::Outgoing : MessageFlag(0));
const auto item = history->makeMessage( const auto item = history->makeMessage({
history->owner().nextLocalMessageId(), .id = history->owner().nextLocalMessageId(),
flags, .flags = flags,
base::unixtime::now(), .date = base::unixtime::now(),
PreparedServiceText{ { text } }); }, PreparedServiceText{ { text } });
return AdminLog::OwnedItem(delegate, item); return AdminLog::OwnedItem(delegate, item);
} }
@ -96,24 +96,16 @@ constexpr auto kMaxWallPaperSlugLength = 255;
bool out) { bool out) {
Expects(history->peer->isUser()); Expects(history->peer->isUser());
const auto flags = MessageFlag::FakeHistoryItem const auto item = history->makeMessage({
| MessageFlag::HasFromId .id = history->nextNonHistoryEntryId(),
| (out ? MessageFlag::Outgoing : MessageFlag(0)); .flags = (MessageFlag::FakeHistoryItem
const auto replyTo = FullReplyTo(); | MessageFlag::HasFromId
const auto viaBotId = UserId(); | (out ? MessageFlag::Outgoing : MessageFlag(0))),
const auto groupedId = uint64(); .from = (out
const auto item = history->makeMessage( ? history->session().userId()
history->nextNonHistoryEntryId(), : peerToUser(history->peer->id)),
flags, .date = base::unixtime::now(),
replyTo, }, TextWithEntities{ text }, MTP_messageMediaEmpty());
viaBotId,
base::unixtime::now(),
out ? history->session().userId() : peerToUser(history->peer->id),
QString(),
TextWithEntities{ text },
MTP_messageMediaEmpty(),
HistoryMessageMarkupData(),
groupedId);
return AdminLog::OwnedItem(delegate, item); return AdminLog::OwnedItem(delegate, item);
} }

View file

@ -319,47 +319,36 @@ PreviewWrap::PreviewWrap(
, _delegate(std::make_unique<PreviewDelegate>(box, _style.get(), [=] { , _delegate(std::make_unique<PreviewDelegate>(box, _style.get(), [=] {
update(); update();
})) }))
, _replyToItem(_history->addNewLocalMessage( , _replyToItem(_history->addNewLocalMessage({
_history->nextNonHistoryEntryId(), .id = _history->nextNonHistoryEntryId(),
(MessageFlag::FakeHistoryItem .flags = (MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId | MessageFlag::HasFromId
| MessageFlag::Post), | MessageFlag::Post),
UserId(), // via .from = _fake->id,
FullReplyTo(), .date = base::unixtime::now(),
base::unixtime::now(), // date }, TextWithEntities{ _peer->isSelf()
_fake->id, ? tr::lng_settings_color_reply(tr::now)
QString(), // postAuthor : tr::lng_settings_color_reply_channel(tr::now),
TextWithEntities{ _peer->isSelf() }, MTP_messageMediaEmpty()))
? tr::lng_settings_color_reply(tr::now) , _replyItem(_history->addNewLocalMessage({
: tr::lng_settings_color_reply_channel(tr::now), .id = _history->nextNonHistoryEntryId(),
}, .flags = (MessageFlag::FakeHistoryItem
MTP_messageMediaEmpty(),
HistoryMessageMarkupData(),
uint64(0)))
, _replyItem(_history->addNewLocalMessage(
_history->nextNonHistoryEntryId(),
(MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId | MessageFlag::HasFromId
| MessageFlag::HasReplyInfo | MessageFlag::HasReplyInfo
| MessageFlag::Post), | MessageFlag::Post),
UserId(), // via .from = _fake->id,
FullReplyTo{ .messageId = _replyToItem->fullId() }, .replyTo = FullReplyTo{.messageId = _replyToItem->fullId() },
base::unixtime::now(), // date .date = base::unixtime::now(),
_fake->id, }, TextWithEntities{ _peer->isSelf()
QString(), // postAuthor ? tr::lng_settings_color_text(tr::now)
TextWithEntities{ _peer->isSelf() : tr::lng_settings_color_text_channel(tr::now),
? tr::lng_settings_color_text(tr::now) }, MTP_messageMediaWebPage(
: tr::lng_settings_color_text_channel(tr::now), MTP_flags(0),
}, MTP_webPagePending(
MTP_messageMediaWebPage(
MTP_flags(0), MTP_flags(0),
MTP_webPagePending( MTP_long(_webpage->id),
MTP_flags(0), MTPstring(),
MTP_long(_webpage->id), MTP_int(0)))))
MTPstring(),
MTP_int(0))),
HistoryMessageMarkupData(),
uint64(0)))
, _element(_replyItem->createView(_delegate.get())) , _element(_replyItem->createView(_delegate.get()))
, _position(0, st::msgMargin.bottom()) { , _position(0, st::msgMargin.bottom()) {
_style->apply(_theme.get()); _style->apply(_theme.get());

View file

@ -77,20 +77,15 @@ AdminLog::OwnedItem GenerateItem(
const QString &text) { const QString &text) {
Expects(history->peer->isUser()); Expects(history->peer->isUser());
const auto item = history->addNewLocalMessage( const auto item = history->addNewLocalMessage({
history->nextNonHistoryEntryId(), .id = history->nextNonHistoryEntryId(),
(MessageFlag::FakeHistoryItem .flags = (MessageFlag::FakeHistoryItem
| MessageFlag::HasFromId | MessageFlag::HasFromId
| MessageFlag::HasReplyInfo), | MessageFlag::HasReplyInfo),
UserId(), // via .from = from,
FullReplyTo{ .messageId = replyTo }, .replyTo = FullReplyTo{ .messageId = replyTo },
base::unixtime::now(), // date .date = base::unixtime::now(),
from, }, TextWithEntities{ .text = text }, MTP_messageMediaEmpty());
QString(), // postAuthor
TextWithEntities{ .text = text },
MTP_messageMediaEmpty(),
HistoryMessageMarkupData(),
uint64(0)); // groupedId
return AdminLog::OwnedItem(delegate, item); return AdminLog::OwnedItem(delegate, item);
} }

View file

@ -27,13 +27,13 @@ constexpr auto kRequestTimeLimit = 60 * crl::time(1000);
[[nodiscard]] MsgId RemoteToLocalMsgId(MsgId id) { [[nodiscard]] MsgId RemoteToLocalMsgId(MsgId id) {
Expects(IsServerMsgId(id)); Expects(IsServerMsgId(id));
return ServerMaxMsgId + id + 1; return ScheduledMaxMsgId + id + 1;
} }
[[nodiscard]] MsgId LocalToRemoteMsgId(MsgId id) { [[nodiscard]] MsgId LocalToRemoteMsgId(MsgId id) {
Expects(IsShortcutMsgId(id)); Expects(IsShortcutMsgId(id));
return (id - ServerMaxMsgId - 1); return (id - ScheduledMaxMsgId - 1);
} }
[[nodiscard]] bool TooEarlyForRequest(crl::time received) { [[nodiscard]] bool TooEarlyForRequest(crl::time received) {
@ -145,6 +145,14 @@ int ShortcutMessages::count(BusinessShortcutId shortcutId) const {
return (i != end(_data)) ? i->second.items.size() : 0; return (i != end(_data)) ? i->second.items.size() : 0;
} }
void ShortcutMessages::apply(const MTPDupdateQuickReplies &update) {
}
void ShortcutMessages::apply(const MTPDupdateNewQuickReply &update) {
}
void ShortcutMessages::apply(const MTPDupdateQuickReplyMessage &update) { void ShortcutMessages::apply(const MTPDupdateQuickReplyMessage &update) {
const auto &message = update.vmessage(); const auto &message = update.vmessage();
const auto shortcutId = BusinessShortcutIdFromMessage(message); const auto shortcutId = BusinessShortcutIdFromMessage(message);

View file

@ -50,6 +50,8 @@ public:
[[nodiscard]] int count(BusinessShortcutId shortcutId) const; [[nodiscard]] int count(BusinessShortcutId shortcutId) const;
[[nodiscard]] MsgId localMessageId(MsgId remoteId) const; [[nodiscard]] MsgId localMessageId(MsgId remoteId) const;
void apply(const MTPDupdateQuickReplies &update);
void apply(const MTPDupdateNewQuickReply &update);
void apply(const MTPDupdateQuickReplyMessage &update); void apply(const MTPDupdateQuickReplyMessage &update);
void apply(const MTPDupdateDeleteQuickReplyMessages &update); void apply(const MTPDupdateDeleteQuickReplyMessages &update);
void apply(const MTPDupdateDeleteQuickReply &update); void apply(const MTPDupdateDeleteQuickReply &update);

View file

@ -879,29 +879,20 @@ not_null<HistoryItem*> DownloadManager::generateItem(
const auto session = document const auto session = document
? &document->session() ? &document->session()
: &photo->session(); : &photo->session();
const auto fromId = previousItem
? previousItem->from()->id
: session->userPeerId();
const auto history = previousItem const auto history = previousItem
? previousItem->history() ? previousItem->history()
: session->data().history(session->user()); : session->data().history(session->user());
const auto flags = MessageFlag::FakeHistoryItem; ;
const auto replyTo = FullReplyTo();
const auto viaBotId = UserId();
const auto date = base::unixtime::now();
const auto caption = TextWithEntities(); const auto caption = TextWithEntities();
const auto make = [&](const auto media) { const auto make = [&](const auto media) {
return history->makeMessage( return history->makeMessage({
history->nextNonHistoryEntryId(), .id = history->nextNonHistoryEntryId(),
flags, .flags = MessageFlag::FakeHistoryItem,
replyTo, .from = (previousItem
viaBotId, ? previousItem->from()->id
date, : session->userPeerId()),
fromId, .date = base::unixtime::now(),
QString(), }, media, caption);
media,
caption,
HistoryMessageMarkupData());
}; };
const auto result = document ? make(document) : make(photo); const auto result = document ? make(document) : make(photo);
_generated.emplace(result); _generated.emplace(result);

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_histories.h" #include "data/data_histories.h"
#include "api/api_text_entities.h" #include "api/api_text_entities.h"
#include "data/business/data_shortcut_messages.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_chat.h" #include "data/data_chat.h"
@ -821,6 +822,7 @@ void Histories::deleteMessages(const MessageIdsList &ids, bool revoke) {
remove.reserve(ids.size()); remove.reserve(ids.size());
base::flat_map<not_null<History*>, QVector<MTPint>> idsByPeer; base::flat_map<not_null<History*>, QVector<MTPint>> idsByPeer;
base::flat_map<not_null<PeerData*>, QVector<MTPint>> scheduledIdsByPeer; base::flat_map<not_null<PeerData*>, QVector<MTPint>> scheduledIdsByPeer;
base::flat_map<BusinessShortcutId, QVector<MTPint>> quickIdsByShortcut;
for (const auto &itemId : ids) { for (const auto &itemId : ids) {
if (const auto item = _owner->message(itemId)) { if (const auto item = _owner->message(itemId)) {
const auto history = item->history(); const auto history = item->history();
@ -834,6 +836,16 @@ void Histories::deleteMessages(const MessageIdsList &ids, bool revoke) {
_owner->scheduledMessages().removeSending(item); _owner->scheduledMessages().removeSending(item);
} }
continue; continue;
} else if (item->isBusinessShortcut()) {
const auto wasOnServer = !item->isSending()
&& !item->hasFailed();
if (wasOnServer) {
quickIdsByShortcut[item->shortcutId()].push_back(MTP_int(
_owner->shortcutMessages().lookupId(item)));
} else {
_owner->shortcutMessages().removeSending(item);
}
continue;
} }
remove.push_back(item); remove.push_back(item);
if (item->isRegular()) { if (item->isRegular()) {
@ -853,6 +865,15 @@ void Histories::deleteMessages(const MessageIdsList &ids, bool revoke) {
peer->session().api().applyUpdates(result); peer->session().api().applyUpdates(result);
}).send(); }).send();
} }
for (const auto &[shortcutId, ids] : quickIdsByShortcut) {
const auto api = &_owner->session().api();
api->request(MTPmessages_DeleteQuickReplyMessages(
MTP_int(shortcutId),
MTP_vector<MTPint>(ids)
)).done([=](const MTPUpdates &result) {
api->applyUpdates(result);
}).send();
}
for (const auto item : remove) { for (const auto item : remove) {
const auto history = item->history(); const auto history = item->history();

View file

@ -34,11 +34,11 @@ constexpr auto kMaxMessagesToDeleteMyTopic = 10;
not_null<History*> history, not_null<History*> history,
TimeId date, TimeId date,
const QString &text) { const QString &text) {
return history->makeMessage( return history->makeMessage({
history->nextNonHistoryEntryId(), .id = history->nextNonHistoryEntryId(),
MessageFlag::FakeHistoryItem, .flags = MessageFlag::FakeHistoryItem,
date, .date = date,
PreparedServiceText{ { .text = text } }); }, PreparedServiceText{ { .text = text } });
} }
[[nodiscard]] bool IsCreating(not_null<History*> history, MsgId rootId) { [[nodiscard]] bool IsCreating(not_null<History*> history, MsgId rootId) {

View file

@ -80,7 +80,7 @@ bool SponsoredMessages::append(not_null<History*> history) {
entryIt->itemFullId = FullMsgId( entryIt->itemFullId = FullMsgId(
history->peer->id, history->peer->id,
_session->data().nextLocalMessageId()); _session->data().nextLocalMessageId());
entryIt->item.reset(history->addNewLocalMessage( entryIt->item.reset(history->addSponsoredMessage(
entryIt->itemFullId.msg, entryIt->itemFullId.msg,
entryIt->sponsored.from, entryIt->sponsored.from,
entryIt->sponsored.textWithEntities)); entryIt->sponsored.textWithEntities));

View file

@ -970,7 +970,7 @@ std::shared_ptr<HistoryItem> Stories::resolveItem(not_null<Story*> story) {
} }
const auto history = _owner->history(story->peer()); const auto history = _owner->history(story->peer());
auto result = std::shared_ptr<HistoryItem>( auto result = std::shared_ptr<HistoryItem>(
history->makeMessage(story).get(), history->makeMessage(StoryIdToMsgId(story->id()), story).get(),
HistoryItem::Destroyer()); HistoryItem::Destroyer());
i->second = result; i->second = result;
return result; return result;

View file

@ -318,6 +318,8 @@ enum class MessageFlag : uint64 {
Sponsored = (1ULL << 42), Sponsored = (1ULL << 42),
ReactionsAreTags = (1ULL << 43), ReactionsAreTags = (1ULL << 43),
ShortcutMessage = (1ULL << 44),
}; };
inline constexpr bool is_flag_type(MessageFlag) { return true; } inline constexpr bool is_flag_type(MessageFlag) { return true; }
using MessageFlags = base::flags<MessageFlag>; using MessageFlags = base::flags<MessageFlag>;

View file

@ -801,13 +801,12 @@ void GenerateItems(
auto message = PreparedServiceText{ text }; auto message = PreparedServiceText{ text };
message.links.push_back(fromLink); message.links.push_back(fromLink);
addPart( addPart(
history->makeMessage( history->makeMessage({
history->nextNonHistoryEntryId(), .id = history->nextNonHistoryEntryId(),
MessageFlag::AdminLogEntry, .flags = MessageFlag::AdminLogEntry,
date, .from = from->id,
std::move(message), .date = date,
peerToUser(from->id), }, std::move(message), photo),
photo),
0, 0,
realId); realId);
}; };
@ -826,23 +825,11 @@ void GenerateItems(
}; };
const auto makeSimpleTextMessage = [&](TextWithEntities &&text) { const auto makeSimpleTextMessage = [&](TextWithEntities &&text) {
const auto bodyFlags = MessageFlag::HasFromId return history->makeMessage({
| MessageFlag::AdminLogEntry; .id = history->nextNonHistoryEntryId(),
const auto bodyReplyTo = FullReplyTo(); .flags = MessageFlag::HasFromId | MessageFlag::AdminLogEntry,
const auto bodyViaBotId = UserId(); .from = from->id,
const auto bodyGroupedId = uint64(); }, std::move(text), MTP_messageMediaEmpty());
return history->makeMessage(
history->nextNonHistoryEntryId(),
bodyFlags,
bodyReplyTo,
bodyViaBotId,
date,
peerToUser(from->id),
QString(),
std::move(text),
MTP_messageMediaEmpty(),
HistoryMessageMarkupData(),
bodyGroupedId);
}; };
const auto addSimpleTextMessage = [&](TextWithEntities &&text) { const auto addSimpleTextMessage = [&](TextWithEntities &&text) {
@ -1145,12 +1132,12 @@ void GenerateItems(
auto message = PreparedServiceText{ text }; auto message = PreparedServiceText{ text };
message.links.push_back(fromLink); message.links.push_back(fromLink);
message.links.push_back(setLink); message.links.push_back(setLink);
addPart(history->makeMessage( addPart(history->makeMessage({
history->nextNonHistoryEntryId(), .id = history->nextNonHistoryEntryId(),
MessageFlag::AdminLogEntry, .flags = MessageFlag::AdminLogEntry,
date, .from = from->id,
std::move(message), .date = date,
peerToUser(from->id))); }, std::move(message)));
} }
}; };
@ -1189,12 +1176,12 @@ void GenerateItems(
auto message = PreparedServiceText{ text }; auto message = PreparedServiceText{ text };
message.links.push_back(fromLink); message.links.push_back(fromLink);
message.links.push_back(setLink); message.links.push_back(setLink);
addPart(history->makeMessage( addPart(history->makeMessage({
history->nextNonHistoryEntryId(), .id = history->nextNonHistoryEntryId(),
MessageFlag::AdminLogEntry, .flags = MessageFlag::AdminLogEntry,
date, .from = from->id,
std::move(message), .date = date,
peerToUser(from->id))); }, std::move(message)));
} }
}; };
@ -1270,12 +1257,12 @@ void GenerateItems(
auto message = PreparedServiceText{ text }; auto message = PreparedServiceText{ text };
message.links.push_back(fromLink); message.links.push_back(fromLink);
message.links.push_back(chatLink); message.links.push_back(chatLink);
addPart(history->makeMessage( addPart(history->makeMessage({
history->nextNonHistoryEntryId(), .id = history->nextNonHistoryEntryId(),
MessageFlag::AdminLogEntry, .flags = MessageFlag::AdminLogEntry,
date, .from = from->id,
std::move(message), .date = date,
peerToUser(from->id))); }, std::move(message)));
} }
}; };
@ -1366,12 +1353,12 @@ void GenerateItems(
auto message = PreparedServiceText{ text }; auto message = PreparedServiceText{ text };
message.links.push_back(fromLink); message.links.push_back(fromLink);
message.links.push_back(link); message.links.push_back(link);
addPart(history->makeMessage( addPart(history->makeMessage({
history->nextNonHistoryEntryId(), .id = history->nextNonHistoryEntryId(),
MessageFlag::AdminLogEntry, .flags = MessageFlag::AdminLogEntry,
date, .from = from->id,
std::move(message), .date = date,
peerToUser(from->id))); }, std::move(message)));
}; };
const auto createParticipantMute = [&](const LogMute &data) { const auto createParticipantMute = [&](const LogMute &data) {
@ -1441,13 +1428,12 @@ void GenerateItems(
if (additional) { if (additional) {
message.links.push_back(std::move(additional)); message.links.push_back(std::move(additional));
} }
addPart(history->makeMessage( addPart(history->makeMessage({
history->nextNonHistoryEntryId(), .id = history->nextNonHistoryEntryId(),
MessageFlag::AdminLogEntry, .flags = MessageFlag::AdminLogEntry,
date, .from = from->id,
std::move(message), .date = date,
peerToUser(from->id), }, std::move(message)));
nullptr));
}; };
const auto createParticipantJoinByInvite = [&]( const auto createParticipantJoinByInvite = [&](

View file

@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_translation.h" #include "history/history_translation.h"
#include "history/history_unread_things.h" #include "history/history_unread_things.h"
#include "dialogs/ui/dialogs_layout.h" #include "dialogs/ui/dialogs_layout.h"
#include "data/business/data_shortcut_messages.h"
#include "data/notify/data_notify_settings.h" #include "data/notify/data_notify_settings.h"
#include "data/stickers/data_stickers.h" #include "data/stickers/data_stickers.h"
#include "data/data_drafts.h" #include "data/data_drafts.h"
@ -71,6 +72,12 @@ constexpr auto kSkipCloudDraftsFor = TimeId(2);
using UpdateFlag = Data::HistoryUpdate::Flag; using UpdateFlag = Data::HistoryUpdate::Flag;
[[nodiscard]] HistoryItemCommonFields WithLocalFlag(
HistoryItemCommonFields fields) {
fields.flags |= MessageFlag::Local;
return fields;
}
} // namespace } // namespace
History::History(not_null<Data::Session*> owner, PeerId peerId) History::History(not_null<Data::Session*> owner, PeerId peerId)
@ -446,17 +453,17 @@ std::vector<not_null<HistoryItem*>> History::createItems(
not_null<HistoryItem*> History::addNewMessage( not_null<HistoryItem*> History::addNewMessage(
MsgId id, MsgId id,
const MTPMessage &msg, const MTPMessage &message,
MessageFlags localFlags, MessageFlags localFlags,
NewMessageType type) { NewMessageType type) {
const auto detachExistingItem = (type == NewMessageType::Unread); const auto detachExisting = (type == NewMessageType::Unread);
const auto item = createItem(id, msg, localFlags, detachExistingItem); const auto item = createItem(id, message, localFlags, detachExisting);
if (type == NewMessageType::Existing || item->mainView()) { if (type == NewMessageType::Existing || item->mainView()) {
return item; return item;
} }
const auto unread = (type == NewMessageType::Unread); const auto unread = (type == NewMessageType::Unread);
if (unread && item->isHistoryEntry()) { if (unread && item->isHistoryEntry()) {
applyMessageChanges(item, msg); applyMessageChanges(item, message);
} }
return addNewItem(item, unread); return addNewItem(item, unread);
} }
@ -585,6 +592,9 @@ not_null<HistoryItem*> History::addNewItem(
if (item->isScheduled()) { if (item->isScheduled()) {
owner().scheduledMessages().appendSending(item); owner().scheduledMessages().appendSending(item);
return item; return item;
} else if (item->isBusinessShortcut()) {
owner().shortcutMessages().appendSending(item);
return item;
} else if (!item->isHistoryEntry()) { } else if (!item->isHistoryEntry()) {
return item; return item;
} }
@ -635,139 +645,54 @@ void History::checkForLoadedAtTop(not_null<HistoryItem*> added) {
} }
not_null<HistoryItem*> History::addNewLocalMessage( not_null<HistoryItem*> History::addNewLocalMessage(
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
UserId viaBotId,
FullReplyTo replyTo,
TimeId date,
PeerId from,
const QString &postAuthor,
const TextWithEntities &text, const TextWithEntities &text,
const MTPMessageMedia &media, const MTPMessageMedia &media) {
HistoryMessageMarkupData &&markup,
uint64 groupedId) {
return addNewItem( return addNewItem(
makeMessage( makeMessage(WithLocalFlag(std::move(fields)), text, media),
id,
flags | MessageFlag::Local,
replyTo,
viaBotId,
date,
from,
postAuthor,
text,
media,
std::move(markup),
groupedId),
true); true);
} }
not_null<HistoryItem*> History::addNewLocalMessage( not_null<HistoryItem*> History::addNewLocalMessage(
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags, not_null<HistoryItem*> forwardOriginal) {
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<HistoryItem*> forwardOriginal,
MsgId topicRootId) {
return addNewItem( return addNewItem(
makeMessage( makeMessage(WithLocalFlag(std::move(fields)), forwardOriginal),
id,
flags | MessageFlag::Local,
date,
from,
postAuthor,
forwardOriginal,
topicRootId),
true); true);
} }
not_null<HistoryItem*> History::addNewLocalMessage( not_null<HistoryItem*> History::addNewLocalMessage(
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
UserId viaBotId,
FullReplyTo replyTo,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<DocumentData*> document, not_null<DocumentData*> document,
const TextWithEntities &caption, const TextWithEntities &caption) {
HistoryMessageMarkupData &&markup) {
return addNewItem( return addNewItem(
makeMessage( makeMessage(WithLocalFlag(std::move(fields)), document, caption),
id,
flags | MessageFlag::Local,
replyTo,
viaBotId,
date,
from,
postAuthor,
document,
caption,
std::move(markup)),
true); true);
} }
not_null<HistoryItem*> History::addNewLocalMessage( not_null<HistoryItem*> History::addNewLocalMessage(
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
UserId viaBotId,
FullReplyTo replyTo,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
const TextWithEntities &caption, const TextWithEntities &caption) {
HistoryMessageMarkupData &&markup) {
return addNewItem( return addNewItem(
makeMessage( makeMessage(WithLocalFlag(std::move(fields)), photo, caption),
id,
flags | MessageFlag::Local,
replyTo,
viaBotId,
date,
from,
postAuthor,
photo,
caption,
std::move(markup)),
true); true);
} }
not_null<HistoryItem*> History::addNewLocalMessage( not_null<HistoryItem*> History::addNewLocalMessage(
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags, not_null<GameData*> game) {
UserId viaBotId,
FullReplyTo replyTo,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<GameData*> game,
HistoryMessageMarkupData &&markup) {
return addNewItem( return addNewItem(
makeMessage( makeMessage(WithLocalFlag(std::move(fields)), game),
id,
flags | MessageFlag::Local,
replyTo,
viaBotId,
date,
from,
postAuthor,
game,
std::move(markup)),
true); true);
} }
not_null<HistoryItem*> History::addNewLocalMessage( not_null<HistoryItem*> History::addSponsoredMessage(
MsgId id, MsgId id,
Data::SponsoredFrom from, Data::SponsoredFrom from,
const TextWithEntities &textWithEntities) { const TextWithEntities &textWithEntities) {
return addNewItem( return addNewItem(
makeMessage( makeMessage(id, from, textWithEntities, nullptr),
id,
from,
textWithEntities,
nullptr),
true); true);
} }

View file

@ -20,6 +20,7 @@ class History;
class HistoryBlock; class HistoryBlock;
class HistoryTranslation; class HistoryTranslation;
class HistoryItem; class HistoryItem;
struct HistoryItemCommonFields;
struct HistoryMessageMarkupData; struct HistoryMessageMarkupData;
class HistoryMainElementDelegateMixin; class HistoryMainElementDelegateMixin;
struct LanguageId; struct LanguageId;
@ -127,11 +128,23 @@ public:
void applyGroupAdminChanges(const base::flat_set<UserId> &changes); void applyGroupAdminChanges(const base::flat_set<UserId> &changes);
template <typename ...Args> template <typename ...Args>
not_null<HistoryItem*> makeMessage(Args &&...args) { not_null<HistoryItem*> makeMessage(MsgId id, Args &&...args) {
return static_cast<HistoryItem*>( return static_cast<HistoryItem*>(
insertItem( insertItem(
std::make_unique<HistoryItem>( std::make_unique<HistoryItem>(
this, this,
id,
std::forward<Args>(args)...)).get());
}
template <typename ...Args>
not_null<HistoryItem*> makeMessage(
HistoryItemCommonFields &&fields,
Args &&...args) {
return static_cast<HistoryItem*>(
insertItem(
std::make_unique<HistoryItem>(
this,
std::move(fields),
std::forward<Args>(args)...)).get()); std::forward<Args>(args)...)).get());
} }
@ -143,62 +156,30 @@ public:
not_null<HistoryItem*> addNewMessage( not_null<HistoryItem*> addNewMessage(
MsgId id, MsgId id,
const MTPMessage &msg, const MTPMessage &message,
MessageFlags localFlags, MessageFlags localFlags,
NewMessageType type); NewMessageType type);
not_null<HistoryItem*> addNewLocalMessage( not_null<HistoryItem*> addNewLocalMessage(
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
UserId viaBotId,
FullReplyTo replyTo,
TimeId date,
PeerId from,
const QString &postAuthor,
const TextWithEntities &text, const TextWithEntities &text,
const MTPMessageMedia &media, const MTPMessageMedia &media);
HistoryMessageMarkupData &&markup,
uint64 groupedId = 0);
not_null<HistoryItem*> addNewLocalMessage( not_null<HistoryItem*> addNewLocalMessage(
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags, not_null<HistoryItem*> forwardOriginal);
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<HistoryItem*> forwardOriginal,
MsgId topicRootId);
not_null<HistoryItem*> addNewLocalMessage( not_null<HistoryItem*> addNewLocalMessage(
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
UserId viaBotId,
FullReplyTo replyTo,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<DocumentData*> document, not_null<DocumentData*> document,
const TextWithEntities &caption, const TextWithEntities &caption);
HistoryMessageMarkupData &&markup);
not_null<HistoryItem*> addNewLocalMessage( not_null<HistoryItem*> addNewLocalMessage(
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
UserId viaBotId,
FullReplyTo replyTo,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
const TextWithEntities &caption, const TextWithEntities &caption);
HistoryMessageMarkupData &&markup);
not_null<HistoryItem*> addNewLocalMessage(
MsgId id,
MessageFlags flags,
UserId viaBotId,
FullReplyTo replyTo,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<GameData*> game,
HistoryMessageMarkupData &&markup);
not_null<HistoryItem*> addNewLocalMessage( not_null<HistoryItem*> addNewLocalMessage(
HistoryItemCommonFields &&fields,
not_null<GameData*> game);
not_null<HistoryItem*> addSponsoredMessage(
MsgId id, MsgId id,
Data::SponsoredFrom from, Data::SponsoredFrom from,
const TextWithEntities &textWithEntities); // sponsored const TextWithEntities &textWithEntities); // sponsored

View file

@ -125,6 +125,14 @@ template <typename T>
return false; return false;
} }
[[nodiscard]] HistoryItemCommonFields ForwardedFields(
HistoryItemCommonFields fields,
not_null<History*> history,
not_null<HistoryItem*> original) {
fields.flags |= NewForwardedFlags(history->peer, fields.from, original);
return fields;
}
} // namespace } // namespace
void HistoryItem::HistoryItem::Destroyer::operator()(HistoryItem *value) { void HistoryItem::HistoryItem::Destroyer::operator()(HistoryItem *value) {
@ -347,12 +355,13 @@ HistoryItem::HistoryItem(
MsgId id, MsgId id,
const MTPDmessage &data, const MTPDmessage &data,
MessageFlags localFlags) MessageFlags localFlags)
: HistoryItem( : HistoryItem(history, {
history, .id = id,
id, .flags = FlagsFromMTP(id, data.vflags().v, localFlags),
FlagsFromMTP(id, data.vflags().v, localFlags), .from = data.vfrom_id() ? peerFromMTP(*data.vfrom_id()) : PeerId(0),
data.vdate().v, .date = data.vdate().v,
data.vfrom_id() ? peerFromMTP(*data.vfrom_id()) : PeerId(0)) { .shortcutId = data.vquick_reply_shortcut_id().value_or_empty(),
}) {
_boostsApplied = data.vfrom_boosts_applied().value_or_empty(); _boostsApplied = data.vfrom_boosts_applied().value_or_empty();
const auto media = data.vmedia(); const auto media = data.vmedia();
@ -406,12 +415,12 @@ HistoryItem::HistoryItem(
MsgId id, MsgId id,
const MTPDmessageService &data, const MTPDmessageService &data,
MessageFlags localFlags) MessageFlags localFlags)
: HistoryItem( : HistoryItem(history, {
history, .id = id,
id, .flags = FlagsFromMTP(id, data.vflags().v, localFlags),
FlagsFromMTP(id, data.vflags().v, localFlags), .from = data.vfrom_id() ? peerFromMTP(*data.vfrom_id()) : PeerId(0),
data.vdate().v, .date = data.vdate().v,
data.vfrom_id() ? peerFromMTP(*data.vfrom_id()) : PeerId(0)) { }) {
if (data.vaction().type() != mtpc_messageActionPhoneCall) { if (data.vaction().type() != mtpc_messageActionPhoneCall) {
createServiceFromMtp(data); createServiceFromMtp(data);
} else { } else {
@ -431,9 +440,7 @@ HistoryItem::HistoryItem(
MessageFlags localFlags) MessageFlags localFlags)
: HistoryItem( : HistoryItem(
history, history,
id, { .id = id, .flags = localFlags },
localFlags,
TimeId(0),
PreparedServiceText{ tr::lng_message_empty( PreparedServiceText{ tr::lng_message_empty(
tr::now, tr::now,
Ui::Text::WithEntities) }) { Ui::Text::WithEntities) }) {
@ -441,13 +448,10 @@ HistoryItem::HistoryItem(
HistoryItem::HistoryItem( HistoryItem::HistoryItem(
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
TimeId date,
PreparedServiceText &&message, PreparedServiceText &&message,
PeerId from,
PhotoData *photo) PhotoData *photo)
: HistoryItem(history, id, flags, date, from) { : HistoryItem(history, fields) {
setServiceText(std::move(message)); setServiceText(std::move(message));
if (photo) { if (photo) {
_media = std::make_unique<Data::MediaPhoto>( _media = std::make_unique<Data::MediaPhoto>(
@ -459,25 +463,16 @@ HistoryItem::HistoryItem(
HistoryItem::HistoryItem( HistoryItem::HistoryItem(
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags, not_null<HistoryItem*> original)
TimeId date, : HistoryItem(history, ForwardedFields(fields, history, original)) {
PeerId from,
const QString &postAuthor,
not_null<HistoryItem*> original,
MsgId topicRootId)
: HistoryItem(
history,
id,
(NewForwardedFlags(history->peer, from, original) | flags),
date,
from) {
const auto peer = history->peer; const auto peer = history->peer;
auto config = CreateConfig(); auto config = CreateConfig();
const auto originalMedia = original->media(); const auto originalMedia = original->media();
const auto dropForwardInfo = original->computeDropForwardedInfo(); const auto dropForwardInfo = original->computeDropForwardedInfo();
const auto topicRootId = fields.replyTo.topicRootId;
config.reply.messageId = config.reply.topMessageId = topicRootId; config.reply.messageId = config.reply.topMessageId = topicRootId;
config.reply.topicPost = (topicRootId != 0) ? 1 : 0; config.reply.topicPost = (topicRootId != 0) ? 1 : 0;
if (const auto originalReply = original->Get<HistoryMessageReply>()) { if (const auto originalReply = original->Get<HistoryMessageReply>()) {
@ -520,8 +515,8 @@ HistoryItem::HistoryItem(
? original->author()->id ? original->author()->id
: PeerId(); : PeerId();
} }
if (flags & MessageFlag::HasPostAuthor) { if (_flags & MessageFlag::HasPostAuthor) {
config.postAuthor = postAuthor; config.postAuthor = fields.postAuthor;
} }
if (const auto fwdViaBot = original->viaBot()) { if (const auto fwdViaBot = original->viaBot()) {
config.viaBotId = peerToUser(fwdViaBot->id); config.viaBotId = peerToUser(fwdViaBot->id);
@ -571,63 +566,28 @@ HistoryItem::HistoryItem(
HistoryItem::HistoryItem( HistoryItem::HistoryItem(
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
FullReplyTo replyTo,
UserId viaBotId,
TimeId date,
PeerId from,
const QString &postAuthor,
const TextWithEntities &textWithEntities, const TextWithEntities &textWithEntities,
const MTPMessageMedia &media, const MTPMessageMedia &media)
HistoryMessageMarkupData &&markup, : HistoryItem(history, fields) {
uint64 groupedId) createComponentsHelper(std::move(fields));
: HistoryItem(
history,
id,
flags,
date,
(flags & MessageFlag::HasFromId) ? from : 0) {
createComponentsHelper(
flags,
replyTo,
viaBotId,
postAuthor,
std::move(markup));
setMedia(media); setMedia(media);
setText(textWithEntities); setText(textWithEntities);
if (groupedId) { if (fields.groupedId) {
setGroupId(MessageGroupId::FromRaw( setGroupId(MessageGroupId::FromRaw(
history->peer->id, history->peer->id,
groupedId, fields.groupedId,
flags & MessageFlag::IsOrWasScheduled)); _flags & MessageFlag::IsOrWasScheduled));
} }
} }
HistoryItem::HistoryItem( HistoryItem::HistoryItem(
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
FullReplyTo replyTo,
UserId viaBotId,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<DocumentData*> document, not_null<DocumentData*> document,
const TextWithEntities &caption, const TextWithEntities &caption)
HistoryMessageMarkupData &&markup) : HistoryItem(history, fields) {
: HistoryItem( createComponentsHelper(std::move(fields));
history,
id,
flags,
date,
(flags & MessageFlag::HasFromId) ? from : 0) {
createComponentsHelper(
flags,
replyTo,
viaBotId,
postAuthor,
std::move(markup));
const auto skipPremiumEffect = !history->session().premium(); const auto skipPremiumEffect = !history->session().premium();
const auto spoiler = false; const auto spoiler = false;
@ -642,28 +602,11 @@ HistoryItem::HistoryItem(
HistoryItem::HistoryItem( HistoryItem::HistoryItem(
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
FullReplyTo replyTo,
UserId viaBotId,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
const TextWithEntities &caption, const TextWithEntities &caption)
HistoryMessageMarkupData &&markup) : HistoryItem(history, fields) {
: HistoryItem( createComponentsHelper(std::move(fields));
history,
id,
flags,
date,
(flags & MessageFlag::HasFromId) ? from : 0) {
createComponentsHelper(
flags,
replyTo,
viaBotId,
postAuthor,
std::move(markup));
const auto spoiler = false; const auto spoiler = false;
_media = std::make_unique<Data::MediaPhoto>(this, photo, spoiler); _media = std::make_unique<Data::MediaPhoto>(this, photo, spoiler);
@ -672,27 +615,10 @@ HistoryItem::HistoryItem(
HistoryItem::HistoryItem( HistoryItem::HistoryItem(
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags, not_null<GameData*> game)
FullReplyTo replyTo, : HistoryItem(history, fields) {
UserId viaBotId, createComponentsHelper(std::move(fields));
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<GameData*> game,
HistoryMessageMarkupData &&markup)
: HistoryItem(
history,
id,
flags,
date,
(flags & MessageFlag::HasFromId) ? from : 0) {
createComponentsHelper(
flags,
replyTo,
viaBotId,
postAuthor,
std::move(markup));
_media = std::make_unique<Data::MediaGame>(this, game); _media = std::make_unique<Data::MediaGame>(this, game);
setTextValue({}); setTextValue({});
@ -704,18 +630,15 @@ HistoryItem::HistoryItem(
Data::SponsoredFrom from, Data::SponsoredFrom from,
const TextWithEntities &textWithEntities, const TextWithEntities &textWithEntities,
HistoryItem *injectedAfter) HistoryItem *injectedAfter)
: HistoryItem( : HistoryItem(history, {
history, .id = id,
id, .flags = (MessageFlag::Local
((history->peer->isChannel() ? MessageFlag::Post : MessageFlag(0)) | MessageFlag::Sponsored
//| (from.peer ? MessageFlag::HasFromId : MessageFlag(0)) | (history->peer->isChannel() ? MessageFlag::Post : MessageFlag(0))),
| MessageFlag::Local), .date = HistoryItem::NewMessageDate(injectedAfter
HistoryItem::NewMessageDate(injectedAfter ? injectedAfter->date()
? injectedAfter->date() : 0),
: 0), }) {
/*from.peer ? from.peer->id : */PeerId(0)) {
_flags |= MessageFlag::Sponsored;
const auto webPageType = !from.externalLink.isEmpty() const auto webPageType = !from.externalLink.isEmpty()
? WebPageType::None ? WebPageType::None
: from.isExactPost : from.isExactPost
@ -758,15 +681,15 @@ HistoryItem::HistoryItem(
HistoryItem::HistoryItem( HistoryItem::HistoryItem(
not_null<History*> history, not_null<History*> history,
MsgId id, const HistoryItemCommonFields &fields)
MessageFlags flags, : id(fields.id)
TimeId date,
PeerId from)
: id(id)
, _history(history) , _history(history)
, _from(from ? history->owner().peer(from) : history->peer) , _from((fields.flags & MessageFlag::HasFromId && fields.from)
, _flags(FinalizeMessageFlags(history, flags)) ? history->owner().peer(fields.from)
, _date(date) { : history->peer)
, _flags(FinalizeMessageFlags(history, fields.flags))
, _date(fields.date)
, _shortcutId(fields.shortcutId) {
if (isHistoryEntry() && IsClientMsgId(id)) { if (isHistoryEntry() && IsClientMsgId(id)) {
_history->registerClientSideMessage(this); _history->registerClientSideMessage(this);
} }
@ -774,15 +697,18 @@ HistoryItem::HistoryItem(
HistoryItem::HistoryItem( HistoryItem::HistoryItem(
not_null<History*> history, not_null<History*> history,
MsgId id,
not_null<Data::Story*> story) not_null<Data::Story*> story)
: id(StoryIdToMsgId(story->id())) : HistoryItem(history, {
, _history(history) .id = id,
, _from(history->peer) .flags = (MessageFlag::Local
, _flags(MessageFlag::Local | MessageFlag::Outgoing
| MessageFlag::Outgoing | MessageFlag::HasFromId
| MessageFlag::FakeHistoryItem | MessageFlag::FakeHistoryItem
| MessageFlag::StoryItem) | MessageFlag::StoryItem),
, _date(story->date()) { .from = history->peer->id,
.date = story->date(),
}) {
setStoryFields(story); setStoryFields(story);
} }
@ -807,6 +733,11 @@ TimeId HistoryItem::NewMessageDate(TimeId scheduled) {
return scheduled ? scheduled : base::unixtime::now(); return scheduled ? scheduled : base::unixtime::now();
} }
TimeId HistoryItem::NewMessageDate(
const Api::SendOptions &options) {
return options.shortcutId ? TimeId() : NewMessageDate(options.scheduled);
}
HistoryServiceDependentData *HistoryItem::GetServiceDependentData() { HistoryServiceDependentData *HistoryItem::GetServiceDependentData() {
if (const auto pinned = Get<HistoryServicePinned>()) { if (const auto pinned = Get<HistoryServicePinned>()) {
return pinned; return pinned;
@ -1603,6 +1534,14 @@ bool HistoryItem::isUserpicSuggestion() const {
return (_flags & MessageFlag::IsUserpicSuggestion); return (_flags & MessageFlag::IsUserpicSuggestion);
} }
BusinessShortcutId HistoryItem::shortcutId() const {
return _shortcutId;
}
bool HistoryItem::isBusinessShortcut() const {
return _shortcutId != 0;
}
void HistoryItem::destroy() { void HistoryItem::destroy() {
_history->destroyMessage(this); _history->destroyMessage(this);
} }
@ -3520,15 +3459,11 @@ TextWithEntities HistoryItem::withLocalEntities(
return textWithEntities; return textWithEntities;
} }
void HistoryItem::createComponentsHelper( void HistoryItem::createComponentsHelper(HistoryItemCommonFields &&fields) {
MessageFlags flags, const auto &replyTo = fields.replyTo;
FullReplyTo replyTo,
UserId viaBotId,
const QString &postAuthor,
HistoryMessageMarkupData &&markup) {
auto config = CreateConfig(); auto config = CreateConfig();
config.viaBotId = viaBotId; config.viaBotId = fields.viaBotId;
if (flags & MessageFlag::HasReplyInfo) { if (fields.flags & MessageFlag::HasReplyInfo) {
config.reply.messageId = replyTo.messageId.msg; config.reply.messageId = replyTo.messageId.msg;
config.reply.storyId = replyTo.storyId.story; config.reply.storyId = replyTo.storyId.story;
config.reply.externalPeerId = replyTo.storyId config.reply.externalPeerId = replyTo.storyId
@ -3567,9 +3502,13 @@ void HistoryItem::createComponentsHelper(
config.reply.quoteOffset = replyTo.quoteOffset; config.reply.quoteOffset = replyTo.quoteOffset;
config.reply.quote = std::move(replyTo.quote); config.reply.quote = std::move(replyTo.quote);
} }
config.markup = std::move(markup); config.markup = std::move(fields.markup);
if (flags & MessageFlag::HasPostAuthor) config.postAuthor = postAuthor; if (fields.flags & MessageFlag::HasPostAuthor) {
if (flags & MessageFlag::HasViews) config.viewsCount = 1; config.postAuthor = fields.postAuthor;
}
if (fields.flags & MessageFlag::HasViews) {
config.viewsCount = 1;
}
createComponents(std::move(config)); createComponents(std::move(config));
} }

View file

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class HiddenSenderInfo; class HiddenSenderInfo;
class History; class History;
struct HistoryMessageReply; struct HistoryMessageReply;
struct HistoryMessageViews; struct HistoryMessageViews;
struct HistoryMessageMarkupData; struct HistoryMessageMarkupData;
@ -28,6 +29,10 @@ struct PreparedServiceText;
class ReplyKeyboard; class ReplyKeyboard;
struct LanguageId; struct LanguageId;
namespace Api {
struct SendOptions;
} // namespace Api
namespace base { namespace base {
template <typename Enum> template <typename Enum>
class enum_mask; class enum_mask;
@ -86,6 +91,19 @@ class Service;
class ServiceMessagePainter; class ServiceMessagePainter;
} // namespace HistoryView } // namespace HistoryView
struct HistoryItemCommonFields {
MsgId id = 0;
MessageFlags flags = 0;
PeerId from = 0;
FullReplyTo replyTo;
TimeId date = 0;
BusinessShortcutId shortcutId = 0;
UserId viaBotId = 0;
QString postAuthor;
uint64 groupedId = 0;
HistoryMessageMarkupData markup;
};
class HistoryItem final : public RuntimeComposer<HistoryItem> { class HistoryItem final : public RuntimeComposer<HistoryItem> {
public: public:
[[nodiscard]] static std::unique_ptr<Data::Media> CreateMedia( [[nodiscard]] static std::unique_ptr<Data::Media> CreateMedia(
@ -114,73 +132,39 @@ public:
Data::SponsoredFrom from, Data::SponsoredFrom from,
const TextWithEntities &textWithEntities, const TextWithEntities &textWithEntities,
HistoryItem *injectedAfter); HistoryItem *injectedAfter);
HistoryItem( // Story wrap.
not_null<History*> history,
MsgId id,
not_null<Data::Story*> story);
HistoryItem( // Local message. HistoryItem( // Local message.
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
FullReplyTo replyTo,
UserId viaBotId,
TimeId date,
PeerId from,
const QString &postAuthor,
const TextWithEntities &textWithEntities, const TextWithEntities &textWithEntities,
const MTPMessageMedia &media, const MTPMessageMedia &media);
HistoryMessageMarkupData &&markup,
uint64 groupedId);
HistoryItem( // Local service message. HistoryItem( // Local service message.
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
TimeId date,
PreparedServiceText &&message, PreparedServiceText &&message,
PeerId from = 0,
PhotoData *photo = nullptr); PhotoData *photo = nullptr);
HistoryItem( // Local forwarded. HistoryItem( // Local forwarded.
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags, not_null<HistoryItem*> original);
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<HistoryItem*> original,
MsgId topicRootId);
HistoryItem( // Local photo. HistoryItem( // Local photo.
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
FullReplyTo replyTo,
UserId viaBotId,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
const TextWithEntities &caption, const TextWithEntities &caption);
HistoryMessageMarkupData &&markup);
HistoryItem( // Local document. HistoryItem( // Local document.
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags,
FullReplyTo replyTo,
UserId viaBotId,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<DocumentData*> document, not_null<DocumentData*> document,
const TextWithEntities &caption, const TextWithEntities &caption);
HistoryMessageMarkupData &&markup);
HistoryItem( // Local game. HistoryItem( // Local game.
not_null<History*> history, not_null<History*> history,
MsgId id, HistoryItemCommonFields &&fields,
MessageFlags flags, not_null<GameData*> game);
FullReplyTo replyTo,
UserId viaBotId,
TimeId date,
PeerId from,
const QString &postAuthor,
not_null<GameData*> game,
HistoryMessageMarkupData &&markup);
HistoryItem(not_null<History*> history, not_null<Data::Story*> story);
~HistoryItem(); ~HistoryItem();
struct Destroyer { struct Destroyer {
@ -210,12 +194,8 @@ public:
[[nodiscard]] bool isSponsored() const; [[nodiscard]] bool isSponsored() const;
[[nodiscard]] bool skipNotification() const; [[nodiscard]] bool skipNotification() const;
[[nodiscard]] bool isUserpicSuggestion() const; [[nodiscard]] bool isUserpicSuggestion() const;
[[nodiscard]] BusinessShortcutId shortcutId() const { [[nodiscard]] BusinessShortcutId shortcutId() const;
return _shortcutId; [[nodiscard]] bool isBusinessShortcut() const;
}
[[nodiscard]] bool isBusinessShortcut() const {
return _shortcutId != 0;
}
void addLogEntryOriginal( void addLogEntryOriginal(
WebPageId localId, WebPageId localId,
@ -473,6 +453,8 @@ public:
[[nodiscard]] TimeId date() const; [[nodiscard]] TimeId date() const;
[[nodiscard]] static TimeId NewMessageDate(TimeId scheduled); [[nodiscard]] static TimeId NewMessageDate(TimeId scheduled);
[[nodiscard]] static TimeId NewMessageDate(
const Api::SendOptions &options);
[[nodiscard]] Data::Media *media() const { [[nodiscard]] Data::Media *media() const {
return _media.get(); return _media.get();
@ -554,17 +536,9 @@ private:
HistoryItem( HistoryItem(
not_null<History*> history, not_null<History*> history,
MsgId id, const HistoryItemCommonFields &fields);
MessageFlags flags,
TimeId date,
PeerId from);
void createComponentsHelper( void createComponentsHelper(HistoryItemCommonFields &&fields);
MessageFlags flags,
FullReplyTo replyTo,
UserId viaBotId,
const QString &postAuthor,
HistoryMessageMarkupData &&markup);
void createComponents(CreateConfig &&config); void createComponents(CreateConfig &&config);
void setupForwardedComponent(const CreateConfig &config); void setupForwardedComponent(const CreateConfig &config);

View file

@ -301,6 +301,7 @@ ReplyFields ReplyFieldsFromMTP(
if (const auto id = data.vreply_to_msg_id().value_or_empty()) { if (const auto id = data.vreply_to_msg_id().value_or_empty()) {
result.messageId = data.is_reply_to_scheduled() result.messageId = data.is_reply_to_scheduled()
? owner->scheduledMessages().localMessageId(id) ? owner->scheduledMessages().localMessageId(id)
AssertIsDebug()
: id; : id;
result.topMessageId result.topMessageId
= data.vreply_to_top_id().value_or(id); = data.vreply_to_top_id().value_or(id);

View file

@ -386,6 +386,9 @@ MessageFlags FlagsFromMTP(
| ((flags & MTP::f_from_id) ? Flag::HasFromId : Flag()) | ((flags & MTP::f_from_id) ? Flag::HasFromId : Flag())
| ((flags & MTP::f_reply_to) ? Flag::HasReplyInfo : Flag()) | ((flags & MTP::f_reply_to) ? Flag::HasReplyInfo : Flag())
| ((flags & MTP::f_reply_markup) ? Flag::HasReplyMarkup : Flag()) | ((flags & MTP::f_reply_markup) ? Flag::HasReplyMarkup : Flag())
| ((flags & MTP::f_quick_reply_shortcut_id)
? Flag::ShortcutMessage
: Flag())
| ((flags & MTP::f_from_scheduled) | ((flags & MTP::f_from_scheduled)
? Flag::IsOrWasScheduled ? Flag::IsOrWasScheduled
: Flag()) : Flag())
@ -598,11 +601,11 @@ not_null<HistoryItem*> GenerateJoinedMessage(
TimeId inviteDate, TimeId inviteDate,
not_null<UserData*> inviter, not_null<UserData*> inviter,
bool viaRequest) { bool viaRequest) {
return history->makeMessage( return history->makeMessage({
history->owner().nextLocalMessageId(), .id = history->owner().nextLocalMessageId(),
MessageFlag::Local | MessageFlag::ShowSimilarChannels, .flags = MessageFlag::Local | MessageFlag::ShowSimilarChannels,
inviteDate, .date = inviteDate,
GenerateJoinedText(history, inviter, viaRequest)); }, GenerateJoinedText(history, inviter, viaRequest));
} }
std::optional<bool> PeerHasThisCall( std::optional<bool> PeerHasThisCall(
@ -657,6 +660,7 @@ std::optional<bool> PeerHasThisCall(
MessageFlags flags) { MessageFlags flags) {
if (!(flags & MessageFlag::FakeHistoryItem) if (!(flags & MessageFlag::FakeHistoryItem)
&& !(flags & MessageFlag::IsOrWasScheduled) && !(flags & MessageFlag::IsOrWasScheduled)
&& !(flags & MessageFlag::ShortcutMessage)
&& !(flags & MessageFlag::AdminLogEntry)) { && !(flags & MessageFlag::AdminLogEntry)) {
flags |= MessageFlag::HistoryEntry; flags |= MessageFlag::HistoryEntry;
if (history->peer->isSelf()) { if (history->peer->isSelf()) {

View file

@ -257,38 +257,32 @@ rpl::producer<QString> PreviewWrap::showLinkSelector(
was->destroy(); was->destroy();
} }
using Flag = MTPDmessageMediaWebPage::Flag; using Flag = MTPDmessageMediaWebPage::Flag;
_draftItem = _history->addNewLocalMessage( _draftItem = _history->addNewLocalMessage({
_history->nextNonHistoryEntryId(), .id = _history->nextNonHistoryEntryId(),
(MessageFlag::FakeHistoryItem .flags = (MessageFlag::FakeHistoryItem
| MessageFlag::Outgoing | MessageFlag::Outgoing
| MessageFlag::HasFromId | MessageFlag::HasFromId
| (webpage.invert ? MessageFlag::InvertMedia : MessageFlag())), | (webpage.invert ? MessageFlag::InvertMedia : MessageFlag())),
UserId(), // via .from = _history->session().userPeerId(),
FullReplyTo(), .date = base::unixtime::now(),
base::unixtime::now(), // date }, HighlightParsedLinks({
_history->session().userPeerId(), message.text,
QString(), // postAuthor TextUtilities::ConvertTextTagsToEntities(message.tags),
HighlightParsedLinks({ }, links), MTP_messageMediaWebPage(
message.text, MTP_flags(Flag()
TextUtilities::ConvertTextTagsToEntities(message.tags), | (webpage.forceLargeMedia
}, links), ? Flag::f_force_large_media
MTP_messageMediaWebPage( : Flag())
MTP_flags(Flag() | (webpage.forceSmallMedia
| (webpage.forceLargeMedia ? Flag::f_force_small_media
? Flag::f_force_large_media : Flag())),
: Flag()) MTP_webPagePending(
| (webpage.forceSmallMedia MTP_flags(webpage.url.isEmpty()
? Flag::f_force_small_media ? MTPDwebPagePending::Flag()
: Flag())), : MTPDwebPagePending::Flag::f_url),
MTP_webPagePending( MTP_long(webpage.id),
MTP_flags(webpage.url.isEmpty() MTP_string(webpage.url),
? MTPDwebPagePending::Flag() MTP_int(0))));
: MTPDwebPagePending::Flag::f_url),
MTP_long(webpage.id),
MTP_string(webpage.url),
MTP_int(0))),
HistoryMessageMarkupData(),
uint64(0)); // groupedId
_element = _draftItem->createView(_delegate.get()); _element = _draftItem->createView(_delegate.get());
_selectType = TextSelectType::Letters; _selectType = TextSelectType::Letters;
_symbol = _selectionStartSymbol = 0; _symbol = _selectionStartSymbol = 0;

View file

@ -188,54 +188,39 @@ bool AboutView::refresh() {
} }
AdminLog::OwnedItem AboutView::makeAboutBot(not_null<BotInfo*> info) { AdminLog::OwnedItem AboutView::makeAboutBot(not_null<BotInfo*> info) {
const auto flags = MessageFlag::FakeAboutView
| MessageFlag::FakeHistoryItem
| MessageFlag::Local;
const auto postAuthor = QString();
const auto date = TimeId(0);
const auto replyTo = FullReplyTo();
const auto viaBotId = UserId(0);
const auto groupedId = uint64(0);
const auto textWithEntities = TextUtilities::ParseEntities( const auto textWithEntities = TextUtilities::ParseEntities(
info->description, info->description,
Ui::ItemTextBotNoMonoOptions().flags); Ui::ItemTextBotNoMonoOptions().flags);
const auto make = [&](auto &&a, auto &&b, auto &&...other) { const auto make = [&](auto &&...args) {
return _history->makeMessage( return _history->makeMessage({
_history->nextNonHistoryEntryId(), .id = _history->nextNonHistoryEntryId(),
flags, .flags = (MessageFlag::FakeAboutView
replyTo, | MessageFlag::FakeHistoryItem
viaBotId, | MessageFlag::Local),
date, .from = _history->peer->id,
_history->peer->id, }, std::forward<decltype(args)>(args)...);
postAuthor,
std::forward<decltype(a)>(a),
std::forward<decltype(b)>(b),
HistoryMessageMarkupData(),
std::forward<decltype(other)>(other)...);
}; };
const auto item = info->document const auto item = info->document
? make(info->document, textWithEntities) ? make(info->document, textWithEntities)
: info->photo : info->photo
? make(info->photo, textWithEntities) ? make(info->photo, textWithEntities)
: make(textWithEntities, MTP_messageMediaEmpty(), groupedId); : make(textWithEntities, MTP_messageMediaEmpty());
return AdminLog::OwnedItem(_delegate, item); return AdminLog::OwnedItem(_delegate, item);
} }
AdminLog::OwnedItem AboutView::makePremiumRequired() { AdminLog::OwnedItem AboutView::makePremiumRequired() {
const auto flags = MessageFlag::FakeAboutView const auto item = _history->makeMessage({
| MessageFlag::FakeHistoryItem .id = _history->nextNonHistoryEntryId(),
| MessageFlag::Local; .flags = (MessageFlag::FakeAboutView
const auto date = TimeId(0); | MessageFlag::FakeHistoryItem
const auto item = _history->makeMessage( | MessageFlag::Local),
_history->nextNonHistoryEntryId(), .from = _history->peer->id,
flags, }, PreparedServiceText{ tr::lng_send_non_premium_text(
date, tr::now,
PreparedServiceText{ tr::lng_send_non_premium_text( lt_user,
tr::now, Ui::Text::Bold(_history->peer->shortName()),
lt_user, Ui::Text::RichLangValue),
Ui::Text::Bold(_history->peer->shortName()), });
Ui::Text::RichLangValue) },
peerToUser(_history->peer->id));
auto result = AdminLog::OwnedItem(_delegate, item); auto result = AdminLog::OwnedItem(_delegate, item);
result->overrideMedia(std::make_unique<ServiceBox>( result->overrideMedia(std::make_unique<ServiceBox>(
result.get(), result.get(),

View file

@ -59,6 +59,7 @@ enum class Context : char {
ContactPreview, ContactPreview,
SavedSublist, SavedSublist,
TTLViewer, TTLViewer,
ShortcutMessages,
}; };
enum class OnlyEmojiAndSpaces : char { enum class OnlyEmojiAndSpaces : char {

View file

@ -1792,7 +1792,7 @@ void ListWidget::updateItemsGeometry() {
if (view->isHidden()) { if (view->isHidden()) {
view->setDisplayDate(false); view->setDisplayDate(false);
} else { } else {
view->setDisplayDate(true); view->setDisplayDate(_context != Context::ShortcutMessages);
view->setAttachToPrevious(false); view->setAttachToPrevious(false);
return i; return i;
} }
@ -2048,7 +2048,8 @@ void ListWidget::checkActivation() {
} }
void ListWidget::paintEvent(QPaintEvent *e) { void ListWidget::paintEvent(QPaintEvent *e) {
if (_controller->contentOverlapped(this, e)) { if ((_context != Context::ShortcutMessages)
&& _controller->contentOverlapped(this, e)) {
return; return;
} }
@ -3737,7 +3738,8 @@ void ListWidget::refreshAttachmentsFromTill(int from, int till) {
} else { } else {
const auto viewDate = view->dateTime(); const auto viewDate = view->dateTime();
const auto nextDate = next->dateTime(); const auto nextDate = next->dateTime();
next->setDisplayDate(nextDate.date() != viewDate.date()); next->setDisplayDate(_context != Context::ShortcutMessages
&& nextDate.date() != viewDate.date());
auto attached = next->computeIsAttachToPrevious(view); auto attached = next->computeIsAttachToPrevious(view);
next->setAttachToPrevious(attached, view); next->setAttachToPrevious(attached, view);
view->setAttachToNext(attached, next); view->setAttachToNext(attached, next);

View file

@ -631,11 +631,11 @@ private:
const not_null<ListDelegate*> _delegate; const not_null<ListDelegate*> _delegate;
const not_null<Window::SessionController*> _controller; const not_null<Window::SessionController*> _controller;
const std::unique_ptr<EmojiInteractions> _emojiInteractions; const std::unique_ptr<EmojiInteractions> _emojiInteractions;
const Context _context;
Data::MessagePosition _aroundPosition; Data::MessagePosition _aroundPosition;
Data::MessagePosition _shownAtPosition; Data::MessagePosition _shownAtPosition;
Data::MessagePosition _initialAroundPosition; Data::MessagePosition _initialAroundPosition;
Context _context;
int _aroundIndex = -1; int _aroundIndex = -1;
int _idsLimit = kMinimalIdsLimit; int _idsLimit = kMinimalIdsLimit;
Data::MessagesSlice _slice; Data::MessagesSlice _slice;

View file

@ -2061,6 +2061,7 @@ bool Message::hasFromPhoto() const {
return !item->out() && !item->history()->peer->isUser(); return !item->out() && !item->history()->peer->isUser();
} break; } break;
case Context::ContactPreview: case Context::ContactPreview:
case Context::ShortcutMessages:
return false; return false;
} }
Unexpected("Context in Message::hasFromPhoto."); Unexpected("Context in Message::hasFromPhoto.");
@ -3268,6 +3269,7 @@ bool Message::hasFromName() const {
return false; return false;
} break; } break;
case Context::ContactPreview: case Context::ContactPreview:
case Context::ShortcutMessages:
return false; return false;
} }
Unexpected("Context in Message::hasFromName."); Unexpected("Context in Message::hasFromName.");
@ -3306,6 +3308,9 @@ bool Message::hasOutLayout() const {
const auto item = data(); const auto item = data();
if (item->history()->peer->isSelf()) { if (item->history()->peer->isSelf()) {
if (const auto forwarded = item->Get<HistoryMessageForwarded>()) { if (const auto forwarded = item->Get<HistoryMessageForwarded>()) {
if (context() == Context::ShortcutMessages) {
return true;
}
return (context() == Context::SavedSublist) return (context() == Context::SavedSublist)
&& (!forwarded->forwardOfForward() && (!forwarded->forwardOfForward()
? (forwarded->originalSender ? (forwarded->originalSender

View file

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_photo_media.h" #include "data/data_photo_media.h"
#include "data/data_document_media.h" #include "data/data_document_media.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h"
#include "history/history_item_reply_markup.h" #include "history/history_item_reply_markup.h"
#include "inline_bots/inline_bot_layout_item.h" #include "inline_bots/inline_bot_layout_item.h"
#include "inline_bots/inline_bot_send_data.h" #include "inline_bots/inline_bot_send_data.h"
@ -376,30 +377,15 @@ bool Result::hasThumbDisplay() const {
void Result::addToHistory( void Result::addToHistory(
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const {
MsgId msgId, fields.flags |= MessageFlag::FromInlineBot;
PeerId fromId, if (_replyMarkup) {
TimeId date, fields.markup = *_replyMarkup;
UserId viaBotId, if (!fields.markup.isNull()) {
FullReplyTo replyTo, fields.flags |= MessageFlag::HasReplyMarkup;
const QString &postAuthor) const { }
flags |= MessageFlag::FromInlineBot;
auto markup = _replyMarkup ? *_replyMarkup : HistoryMessageMarkupData();
if (!markup.isNull()) {
flags |= MessageFlag::HasReplyMarkup;
} }
sendData->addToHistory( sendData->addToHistory(this, history, std::move(fields));
this,
history,
flags,
msgId,
fromId,
date,
viaBotId,
replyTo,
postAuthor,
std::move(markup));
} }
QString Result::getErrorOnSend(not_null<History*> history) const { QString Result::getErrorOnSend(not_null<History*> history) const {

View file

@ -16,6 +16,7 @@ class FileLoader;
class History; class History;
class UserData; class UserData;
struct HistoryMessageMarkupData; struct HistoryMessageMarkupData;
struct HistoryItemCommonFields;
namespace Data { namespace Data {
class LocationPoint; class LocationPoint;
@ -64,13 +65,7 @@ public:
void addToHistory( void addToHistory(
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const;
MsgId msgId,
PeerId fromId,
TimeId date,
UserId viaBotId,
FullReplyTo replyTo,
const QString &postAuthor) const;
QString getErrorOnSend(not_null<History*> history) const; QString getErrorOnSend(not_null<History*> history) const;
// interface for Layout:: usage // interface for Layout:: usage

View file

@ -31,29 +31,15 @@ QString SendData::getLayoutDescription(const Result *owner) const {
void SendDataCommon::addToHistory( void SendDataCommon::addToHistory(
const Result *owner, const Result *owner,
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const {
MsgId msgId, auto distinct = getSentMessageFields();
PeerId fromId, if (fields.replyTo) {
TimeId date, fields.flags |= MessageFlag::HasReplyInfo;
UserId viaBotId,
FullReplyTo replyTo,
const QString &postAuthor,
HistoryMessageMarkupData &&markup) const {
auto fields = getSentMessageFields();
if (replyTo) {
flags |= MessageFlag::HasReplyInfo;
} }
history->addNewLocalMessage( history->addNewLocalMessage(
msgId, std::move(fields),
flags, std::move(distinct.text),
viaBotId, std::move(distinct.media));
replyTo,
date,
fromId,
postAuthor,
std::move(fields.text),
std::move(fields.media),
std::move(markup));
} }
QString SendDataCommon::getErrorOnSend( QString SendDataCommon::getErrorOnSend(
@ -113,25 +99,11 @@ QString SendContact::getLayoutDescription(const Result *owner) const {
void SendPhoto::addToHistory( void SendPhoto::addToHistory(
const Result *owner, const Result *owner,
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const {
MsgId msgId,
PeerId fromId,
TimeId date,
UserId viaBotId,
FullReplyTo replyTo,
const QString &postAuthor,
HistoryMessageMarkupData &&markup) const {
history->addNewLocalMessage( history->addNewLocalMessage(
msgId, std::move(fields),
flags,
viaBotId,
replyTo,
date,
fromId,
postAuthor,
_photo, _photo,
{ _message, _entities }, { _message, _entities });
std::move(markup));
} }
QString SendPhoto::getErrorOnSend( QString SendPhoto::getErrorOnSend(
@ -144,25 +116,11 @@ QString SendPhoto::getErrorOnSend(
void SendFile::addToHistory( void SendFile::addToHistory(
const Result *owner, const Result *owner,
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const {
MsgId msgId,
PeerId fromId,
TimeId date,
UserId viaBotId,
FullReplyTo replyTo,
const QString &postAuthor,
HistoryMessageMarkupData &&markup) const {
history->addNewLocalMessage( history->addNewLocalMessage(
msgId, std::move(fields),
flags,
viaBotId,
replyTo,
date,
fromId,
postAuthor,
_document, _document,
{ _message, _entities }, { _message, _entities });
std::move(markup));
} }
QString SendFile::getErrorOnSend( QString SendFile::getErrorOnSend(
@ -175,24 +133,8 @@ QString SendFile::getErrorOnSend(
void SendGame::addToHistory( void SendGame::addToHistory(
const Result *owner, const Result *owner,
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const {
MsgId msgId, history->addNewLocalMessage(std::move(fields), _game);
PeerId fromId,
TimeId date,
UserId viaBotId,
FullReplyTo replyTo,
const QString &postAuthor,
HistoryMessageMarkupData &&markup) const {
history->addNewLocalMessage(
msgId,
flags,
viaBotId,
replyTo,
date,
fromId,
postAuthor,
_game,
std::move(markup));
} }
QString SendGame::getErrorOnSend( QString SendGame::getErrorOnSend(

View file

@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_location_manager.h" #include "history/history_location_manager.h"
struct HistoryMessageMarkupData; struct HistoryItemCommonFields;
namespace Main { namespace Main {
class Session; class Session;
@ -43,14 +43,7 @@ public:
virtual void addToHistory( virtual void addToHistory(
const Result *owner, const Result *owner,
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const = 0;
MsgId msgId,
PeerId fromId,
TimeId date,
UserId viaBotId,
FullReplyTo replyTo,
const QString &postAuthor,
HistoryMessageMarkupData &&markup) const = 0;
virtual QString getErrorOnSend( virtual QString getErrorOnSend(
const Result *owner, const Result *owner,
not_null<History*> history) const = 0; not_null<History*> history) const = 0;
@ -85,14 +78,7 @@ public:
void addToHistory( void addToHistory(
const Result *owner, const Result *owner,
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const override;
MsgId msgId,
PeerId fromId,
TimeId date,
UserId viaBotId,
FullReplyTo replyTo,
const QString &postAuthor,
HistoryMessageMarkupData &&markup) const override;
QString getErrorOnSend( QString getErrorOnSend(
const Result *owner, const Result *owner,
@ -253,14 +239,7 @@ public:
void addToHistory( void addToHistory(
const Result *owner, const Result *owner,
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const override;
MsgId msgId,
PeerId fromId,
TimeId date,
UserId viaBotId,
FullReplyTo replyTo,
const QString &postAuthor,
HistoryMessageMarkupData &&markup) const override;
QString getErrorOnSend( QString getErrorOnSend(
const Result *owner, const Result *owner,
@ -294,14 +273,7 @@ public:
void addToHistory( void addToHistory(
const Result *owner, const Result *owner,
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const override;
MsgId msgId,
PeerId fromId,
TimeId date,
UserId viaBotId,
FullReplyTo replyTo,
const QString &postAuthor,
HistoryMessageMarkupData &&markup) const override;
QString getErrorOnSend( QString getErrorOnSend(
const Result *owner, const Result *owner,
@ -329,14 +301,7 @@ public:
void addToHistory( void addToHistory(
const Result *owner, const Result *owner,
not_null<History*> history, not_null<History*> history,
MessageFlags flags, HistoryItemCommonFields &&fields) const override;
MsgId msgId,
PeerId fromId,
TimeId date,
UserId viaBotId,
FullReplyTo replyTo,
const QString &postAuthor,
HistoryMessageMarkupData &&markup) const override;
QString getErrorOnSend( QString getErrorOnSend(
const Result *owner, const Result *owner,

View file

@ -131,23 +131,12 @@ private:
not_null<History*> history) { not_null<History*> history) {
Expects(history->peer->isUser()); Expects(history->peer->isUser());
const auto flags = MessageFlag::FakeHistoryItem const auto item = history->makeMessage({
| MessageFlag::HasFromId; .id = history->nextNonHistoryEntryId(),
const auto replyTo = FullReplyTo(); .flags = MessageFlag::FakeHistoryItem | MessageFlag::HasFromId,
const auto viaBotId = UserId(); .from = history->peer->id,
const auto groupedId = uint64(); .date = base::unixtime::now(),
const auto item = history->makeMessage( }, TextWithEntities(), MTP_messageMediaEmpty());
history->nextNonHistoryEntryId(),
flags,
replyTo,
viaBotId,
base::unixtime::now(),
peerToUser(history->peer->id),
QString(),
TextWithEntities(),
MTP_messageMediaEmpty(),
HistoryMessageMarkupData(),
groupedId);
return AdminLog::OwnedItem(delegate, item); return AdminLog::OwnedItem(delegate, item);
} }

View file

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/tabbed_selector.h" #include "chat_helpers/tabbed_selector.h"
#include "core/file_utilities.h" #include "core/file_utilities.h"
#include "core/mime_type.h" #include "core/mime_type.h"
#include "data/business/data_shortcut_messages.h"
#include "data/data_message_reaction_id.h" #include "data/data_message_reaction_id.h"
#include "data/data_premium_limits.h" #include "data/data_premium_limits.h"
#include "data/data_session.h" #include "data/data_session.h"
@ -75,6 +76,8 @@ public:
} }
[[nodiscard]] rpl::producer<QString> title() override; [[nodiscard]] rpl::producer<QString> title() override;
[[nodiscard]] rpl::producer<> sectionShowBack() override;
void setInnerFocus() override;
bool paintOuter( bool paintOuter(
not_null<QWidget*> outer, not_null<QWidget*> outer,
@ -82,6 +85,8 @@ public:
QRect clip) override; QRect clip) override;
private: private:
void outerResized(QSize outer);
// ListDelegate interface. // ListDelegate interface.
Context listContext() override; Context listContext() override;
bool listScrollTo(int top, bool syntetic = true) override; bool listScrollTo(int top, bool syntetic = true) override;
@ -154,7 +159,11 @@ private:
QPointer<Ui::RpWidget> createPinnedToBottom( QPointer<Ui::RpWidget> createPinnedToBottom(
not_null<Ui::RpWidget*> parent) override; not_null<Ui::RpWidget*> parent) override;
void setupComposeControls(); void setupComposeControls();
void processScroll();
void updateInnerVisibleArea();
void pushReplyReturn(not_null<HistoryItem*> item);
void checkReplyReturns();
void uploadFile(const QByteArray &fileContent, SendMediaType type); void uploadFile(const QByteArray &fileContent, SendMediaType type);
bool confirmSendingFiles( bool confirmSendingFiles(
@ -234,6 +243,7 @@ private:
QPointer<ListWidget> _inner; QPointer<ListWidget> _inner;
std::unique_ptr<Ui::RpWidget> _controlsWrap; std::unique_ptr<Ui::RpWidget> _controlsWrap;
std::unique_ptr<ComposeControls> _composeControls; std::unique_ptr<ComposeControls> _composeControls;
rpl::event_stream<> _showBackRequests;
bool _skipScrollEvent = false; bool _skipScrollEvent = false;
std::unique_ptr<StickerToast> _stickerToast; std::unique_ptr<StickerToast> _stickerToast;
@ -294,10 +304,17 @@ ShortcutMessages::ShortcutMessages(
this, this,
controller, controller,
static_cast<ListDelegate*>(this)); static_cast<ListDelegate*>(this));
//_scroll->scrolls(
//) | rpl::start_with_next([=] { _scroll->sizeValue() | rpl::filter([](QSize size) {
// onScroll(); return !size.isEmpty();
//}, lifetime()); }) | rpl::start_with_next([=](QSize size) {
outerResized(size);
}, lifetime());
_scroll->scrolls(
) | rpl::start_with_next([=] {
processScroll();
}, lifetime());
_inner->editMessageRequested( _inner->editMessageRequested(
) | rpl::start_with_next([=](auto fullId) { ) | rpl::start_with_next([=](auto fullId) {
@ -312,10 +329,10 @@ ShortcutMessages::ShortcutMessages(
{ {
auto emptyInfo = base::make_unique_q<EmptyListBubbleWidget>( auto emptyInfo = base::make_unique_q<EmptyListBubbleWidget>(
_inner, _inner,
controller->chatStyle(), _style.get(),
st::msgServicePadding); st::msgServicePadding);
const auto emptyText = Ui::Text::Semibold( const auto emptyText = Ui::Text::Semibold(
tr::lng_scheduled_messages_empty(tr::now)); u"give me your money.."_q);
emptyInfo->setText(emptyText); emptyInfo->setText(emptyText);
_inner->setEmptyInfoWidget(std::move(emptyInfo)); _inner->setEmptyInfoWidget(std::move(emptyInfo));
} }
@ -335,6 +352,31 @@ rpl::producer<QString> ShortcutMessages::title() {
return rpl::single(u"Editing messages list"_q); return rpl::single(u"Editing messages list"_q);
} }
void ShortcutMessages::processScroll() {
if (_skipScrollEvent) {
return;
}
updateInnerVisibleArea();
}
void ShortcutMessages::updateInnerVisibleArea() {
if (!_inner->animatedScrolling()) {
checkReplyReturns();
}
const auto scrollTop = _scroll->scrollTop();
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
_cornerButtons.updateJumpDownVisibility();
_cornerButtons.updateUnreadThingsVisibility();
}
rpl::producer<> ShortcutMessages::sectionShowBack() {
return _showBackRequests.events();
}
void ShortcutMessages::setInnerFocus() {
_composeControls->focus();
}
bool ShortcutMessages::paintOuter( bool ShortcutMessages::paintOuter(
not_null<QWidget*> outer, not_null<QWidget*> outer,
int maxVisibleHeight, int maxVisibleHeight,
@ -349,6 +391,29 @@ bool ShortcutMessages::paintOuter(
return true; return true;
} }
void ShortcutMessages::outerResized(QSize outer) {
const auto contentWidth = outer.width();
const auto newScrollTop = _scroll->isHidden()
? std::nullopt
: _scroll->scrollTop()
? base::make_optional(_scroll->scrollTop())
: 0;
_skipScrollEvent = true;
_inner->resizeToWidth(contentWidth, _scroll->height());
resize(width(), _inner->height());
_skipScrollEvent = false;
if (!_scroll->isHidden()) {
if (newScrollTop) {
_scroll->scrollToY(*newScrollTop);
}
updateInnerVisibleArea();
}
_composeControls->setAutocompleteBoundingRect(_scroll->geometry());
_cornerButtons.updatePositions();
}
void ShortcutMessages::setupComposeControls() { void ShortcutMessages::setupComposeControls() {
_composeControls->setHistory({ _composeControls->setHistory({
.history = _history.get(), .history = _history.get(),
@ -446,10 +511,10 @@ void ShortcutMessages::setupComposeControls() {
if (action == Ui::InputField::MimeAction::Check) { if (action == Ui::InputField::MimeAction::Check) {
return Core::CanSendFiles(data); return Core::CanSendFiles(data);
} else if (action == Ui::InputField::MimeAction::Insert) { } else if (action == Ui::InputField::MimeAction::Insert) {
//return confirmSendingFiles( return confirmSendingFiles(
// data, data,
// std::nullopt, std::nullopt,
// Core::ReadMimeText(data));#TODO Core::ReadMimeText(data));
} }
Unexpected("action in MimeData hook."); Unexpected("action in MimeData hook.");
}); });
@ -480,22 +545,24 @@ QPointer<Ui::RpWidget> ShortcutMessages::createPinnedToBottom(
_controlsWrap.get(), _controlsWrap.get(),
_controller, _controller,
[=](not_null<DocumentData*> emoji) { listShowPremiumToast(emoji); }, [=](not_null<DocumentData*> emoji) { listShowPremiumToast(emoji); },
ComposeControls::Mode::Scheduled, ComposeControls::Mode::Normal,
SendMenu::Type::Disabled); SendMenu::Type::Disabled);
setupComposeControls(); setupComposeControls();
showAtEnd();
return _controlsWrap.get(); return _controlsWrap.get();
} }
Context ShortcutMessages::listContext() { Context ShortcutMessages::listContext() {
return Context::History; return Context::ShortcutMessages;
} }
bool ShortcutMessages::listScrollTo(int top, bool syntetic) { bool ShortcutMessages::listScrollTo(int top, bool syntetic) {
top = std::clamp(top, 0, _scroll->scrollTopMax()); top = std::clamp(top, 0, _scroll->scrollTopMax());
if (_scroll->scrollTop() == top) { if (_scroll->scrollTop() == top) {
//updateInnerVisibleArea(); updateInnerVisibleArea();
return false; return false;
} }
_scroll->scrollToY(top); _scroll->scrollToY(top);
@ -509,7 +576,7 @@ void ShortcutMessages::listCancelRequest() {
} else if (_composeControls->handleCancelRequest()) { } else if (_composeControls->handleCancelRequest()) {
return; return;
} }
_controller->showBackFromStack(); _showBackRequests.fire({});
} }
void ShortcutMessages::listDeleteRequest() { void ShortcutMessages::listDeleteRequest() {
@ -525,13 +592,11 @@ rpl::producer<Data::MessagesSlice> ShortcutMessages::listSource(
int limitBefore, int limitBefore,
int limitAfter) { int limitAfter) {
const auto data = &_controller->session().data(); const auto data = &_controller->session().data();
//return rpl::single(rpl::empty) | rpl::then( return rpl::single(rpl::empty) | rpl::then(
// data->scheduledMessages().updates(_history) data->shortcutMessages().updates(_shortcutId)
//) | rpl::map([=] { ) | rpl::map([=] {
// return data->scheduledMessages().list(_history); return data->shortcutMessages().list(_shortcutId);
//}) | rpl::after_next([=](const Data::MessagesSlice &slice) { });
// highlightSingleNewMessage(slice);
//});
return rpl::never<Data::MessagesSlice>(); return rpl::never<Data::MessagesSlice>();
} }
@ -698,12 +763,12 @@ std::optional<bool> ShortcutMessages::cornerButtonsDownShown() {
|| _composeControls->isTTLButtonShown()) { || _composeControls->isTTLButtonShown()) {
return false; return false;
} }
//const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; const auto top = _scroll->scrollTop() + st::historyToDownShownAfter;
//if (top < _scroll->scrollTopMax() || _cornerButtons.replyReturn()) { if (top < _scroll->scrollTopMax() || _cornerButtons.replyReturn()) {
// return true; return true;
//} else if (_inner->loadedAtBottomKnown()) { } else if (_inner->loadedAtBottomKnown()) {
// return !_inner->loadedAtBottom(); return !_inner->loadedAtBottom();
//} }
return std::nullopt; return std::nullopt;
} }
@ -717,10 +782,31 @@ bool ShortcutMessages::cornerButtonsHas(CornerButtonType type) {
return (type == CornerButtonType::Down); return (type == CornerButtonType::Down);
} }
void ShortcutMessages::pushReplyReturn(not_null<HistoryItem*> item) {
if (item->shortcutId() == _shortcutId) {
_cornerButtons.pushReplyReturn(item);
}
}
void ShortcutMessages::checkReplyReturns() {
const auto currentTop = _scroll->scrollTop();
while (const auto replyReturn = _cornerButtons.replyReturn()) {
const auto position = replyReturn->position();
const auto scrollTop = _inner->scrollTopForPosition(position);
const auto below = scrollTop
? (currentTop >= std::min(*scrollTop, _scroll->scrollTopMax()))
: _inner->isBelowPosition(position);
if (below) {
_cornerButtons.calculateNextReplyReturn();
} else {
break;
}
}
}
void ShortcutMessages::uploadFile( void ShortcutMessages::uploadFile(
const QByteArray &fileContent, const QByteArray &fileContent,
SendMediaType type) { SendMediaType type) {
// #TODO replies schedule
_session->api().sendFile(fileContent, type, prepareSendAction({})); _session->api().sendFile(fileContent, type, prepareSendAction({}));
} }
@ -773,11 +859,6 @@ void ShortcutMessages::send() {
return; return;
} }
send({}); send({});
// #TODO replies schedule
//const auto callback = [=](Api::SendOptions options) { send(options); };
//Ui::show(
// PrepareScheduleBox(this, sendMenuType(), callback),
// Ui::LayerOption::KeepOther);
} }
void ShortcutMessages::sendVoice(ComposeControls::VoiceToSend &&data) { void ShortcutMessages::sendVoice(ComposeControls::VoiceToSend &&data) {
@ -933,7 +1014,7 @@ bool ShortcutMessages::confirmSendingFiles(
_composeControls->getTextWithAppliedMarkdown(), _composeControls->getTextWithAppliedMarkdown(),
_history->peer, _history->peer,
Api::SendType::Normal, Api::SendType::Normal,
SendMenu::Type::SilentOnly); // #TODO replies schedule SendMenu::Type::Disabled);
box->setConfirmedCallback(crl::guard(this, [=]( box->setConfirmedCallback(crl::guard(this, [=](
Ui::PreparedList &&list, Ui::PreparedList &&list,

View file

@ -273,24 +273,14 @@ AdminLog::OwnedItem GenerateCommentItem(
if (data.comment.isEmpty()) { if (data.comment.isEmpty()) {
return nullptr; return nullptr;
} }
const auto flags = MessageFlag::HasFromId const auto item = history->makeMessage({
| MessageFlag::Outgoing .id = history->nextNonHistoryEntryId(),
| MessageFlag::FakeHistoryItem; .flags = (MessageFlag::HasFromId
const auto replyTo = FullReplyTo(); | MessageFlag::Outgoing
const auto viaBotId = UserId(); | MessageFlag::FakeHistoryItem),
const auto groupedId = uint64(); .from = history->session().userPeerId(),
const auto item = history->makeMessage( .date = base::unixtime::now(),
history->nextNonHistoryEntryId(), }, TextWithEntities{ data.comment }, MTP_messageMediaEmpty());
flags,
replyTo,
viaBotId,
base::unixtime::now(),
history->session().userId(),
QString(),
TextWithEntities{ data.comment },
MTP_messageMediaEmpty(),
HistoryMessageMarkupData(),
groupedId);
return AdminLog::OwnedItem(delegate, item); return AdminLog::OwnedItem(delegate, item);
} }
@ -298,29 +288,19 @@ AdminLog::OwnedItem GenerateContactItem(
not_null<HistoryView::ElementDelegate*> delegate, not_null<HistoryView::ElementDelegate*> delegate,
not_null<History*> history, not_null<History*> history,
const Contact &data) { const Contact &data) {
const auto replyTo = FullReplyTo(); const auto item = history->makeMessage({
const auto viaBotId = UserId(); .id = history->nextNonHistoryEntryId(),
const auto postAuthor = QString(); .flags = (MessageFlag::HasFromId
const auto groupedId = uint64();
const auto item = history->makeMessage(
history->nextNonHistoryEntryId(),
(MessageFlag::HasFromId
| MessageFlag::Outgoing | MessageFlag::Outgoing
| MessageFlag::FakeHistoryItem), | MessageFlag::FakeHistoryItem),
replyTo, .from = history->session().userPeerId(),
viaBotId, .date = base::unixtime::now(),
base::unixtime::now(), }, TextWithEntities(), MTP_messageMediaContact(
history->session().userPeerId(), MTP_string(data.phone),
postAuthor, MTP_string(data.firstName),
TextWithEntities(), MTP_string(data.lastName),
MTP_messageMediaContact( MTP_string(), // vcard
MTP_string(data.phone), MTP_long(0))); // user_id
MTP_string(data.firstName),
MTP_string(data.lastName),
MTP_string(), // vcard
MTP_long(0)), // user_id
HistoryMessageMarkupData(),
groupedId);
return AdminLog::OwnedItem(delegate, item); return AdminLog::OwnedItem(delegate, item);
} }