mirror of https://github.com/procxx/kepka.git
Allow sending scheduled messages.
This commit is contained in:
parent
caef7dde24
commit
03cdddfe18
|
@ -40,7 +40,9 @@ void SendExistingMedia(
|
||||||
message.action.generateLocal = true;
|
message.action.generateLocal = true;
|
||||||
api->sendAction(message.action);
|
api->sendAction(message.action);
|
||||||
|
|
||||||
const auto newId = FullMsgId(peerToChannel(peer->id), clientMsgId());
|
const auto newId = FullMsgId(
|
||||||
|
peerToChannel(peer->id),
|
||||||
|
session->data().nextLocalMessageId());
|
||||||
const auto randomId = rand_value<uint64>();
|
const auto randomId = rand_value<uint64>();
|
||||||
|
|
||||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
||||||
|
@ -84,6 +86,13 @@ void SendExistingMedia(
|
||||||
const auto replyTo = message.action.replyTo;
|
const auto replyTo = message.action.replyTo;
|
||||||
const auto captionText = caption.text;
|
const auto captionText = caption.text;
|
||||||
|
|
||||||
|
if (message.action.options.scheduled) {
|
||||||
|
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||||
|
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||||
|
} else {
|
||||||
|
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||||
|
}
|
||||||
|
|
||||||
session->data().registerMessageRandomId(randomId, newId);
|
session->data().registerMessageRandomId(randomId, newId);
|
||||||
|
|
||||||
history->addNewLocalMessage(
|
history->addNewLocalMessage(
|
||||||
|
@ -92,7 +101,7 @@ void SendExistingMedia(
|
||||||
clientFlags,
|
clientFlags,
|
||||||
0,
|
0,
|
||||||
replyTo,
|
replyTo,
|
||||||
base::unixtime::now(),
|
HistoryItem::NewMessageDate(message.action.options.scheduled),
|
||||||
messageFromId,
|
messageFromId,
|
||||||
messagePostAuthor,
|
messagePostAuthor,
|
||||||
media,
|
media,
|
||||||
|
@ -111,7 +120,7 @@ void SendExistingMedia(
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
sentEntities,
|
sentEntities,
|
||||||
MTP_int(0) // schedule_date
|
MTP_int(message.action.options.scheduled)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
api->applyUpdates(result, randomId);
|
api->applyUpdates(result, randomId);
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "data/data_sparse_ids.h"
|
#include "data/data_sparse_ids.h"
|
||||||
#include "data/data_search_controller.h"
|
#include "data/data_search_controller.h"
|
||||||
|
#include "data/data_scheduled_messages.h"
|
||||||
#include "data/data_channel_admins.h"
|
#include "data/data_channel_admins.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
@ -4427,6 +4428,12 @@ void ApiWrap::forwardMessages(
|
||||||
if (silentPost) {
|
if (silentPost) {
|
||||||
sendFlags |= MTPmessages_ForwardMessages::Flag::f_silent;
|
sendFlags |= MTPmessages_ForwardMessages::Flag::f_silent;
|
||||||
}
|
}
|
||||||
|
if (action.options.scheduled) {
|
||||||
|
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||||
|
sendFlags |= MTPmessages_ForwardMessages::Flag::f_schedule_date;
|
||||||
|
} else {
|
||||||
|
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||||
|
}
|
||||||
|
|
||||||
auto forwardFrom = items.front()->history()->peer;
|
auto forwardFrom = items.front()->history()->peer;
|
||||||
auto currentGroupId = items.front()->groupId();
|
auto currentGroupId = items.front()->groupId();
|
||||||
|
@ -4448,7 +4455,7 @@ void ApiWrap::forwardMessages(
|
||||||
MTP_vector<MTPint>(ids),
|
MTP_vector<MTPint>(ids),
|
||||||
MTP_vector<MTPlong>(randomIds),
|
MTP_vector<MTPlong>(randomIds),
|
||||||
peer->input,
|
peer->input,
|
||||||
MTP_int(0) // schedule_date
|
MTP_int(action.options.scheduled)
|
||||||
)).done([=, callback = std::move(successCallback)](
|
)).done([=, callback = std::move(successCallback)](
|
||||||
const MTPUpdates &updates) {
|
const MTPUpdates &updates) {
|
||||||
applyUpdates(updates);
|
applyUpdates(updates);
|
||||||
|
@ -4480,7 +4487,7 @@ void ApiWrap::forwardMessages(
|
||||||
if (const auto message = item->toHistoryMessage()) {
|
if (const auto message = item->toHistoryMessage()) {
|
||||||
const auto newId = FullMsgId(
|
const auto newId = FullMsgId(
|
||||||
peerToChannel(peer->id),
|
peerToChannel(peer->id),
|
||||||
clientMsgId());
|
session().data().nextLocalMessageId());
|
||||||
const auto self = _session->user();
|
const auto self = _session->user();
|
||||||
const auto messageFromId = channelPost
|
const auto messageFromId = channelPost
|
||||||
? UserId(0)
|
? UserId(0)
|
||||||
|
@ -4492,7 +4499,7 @@ void ApiWrap::forwardMessages(
|
||||||
newId.msg,
|
newId.msg,
|
||||||
flags,
|
flags,
|
||||||
clientFlags,
|
clientFlags,
|
||||||
base::unixtime::now(),
|
HistoryItem::NewMessageDate(action.options.scheduled),
|
||||||
messageFromId,
|
messageFromId,
|
||||||
messagePostAuthor,
|
messagePostAuthor,
|
||||||
message);
|
message);
|
||||||
|
@ -4554,7 +4561,9 @@ void ApiWrap::sendSharedContact(
|
||||||
const auto history = action.history;
|
const auto history = action.history;
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
|
|
||||||
const auto newId = FullMsgId(history->channelId(), clientMsgId());
|
const auto newId = FullMsgId(
|
||||||
|
history->channelId(),
|
||||||
|
session().data().nextLocalMessageId());
|
||||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||||
|
|
||||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
||||||
|
@ -4571,6 +4580,11 @@ void ApiWrap::sendSharedContact(
|
||||||
} else {
|
} else {
|
||||||
flags |= MTPDmessage::Flag::f_from_id;
|
flags |= MTPDmessage::Flag::f_from_id;
|
||||||
}
|
}
|
||||||
|
if (action.options.scheduled) {
|
||||||
|
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||||
|
} else {
|
||||||
|
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||||
|
}
|
||||||
const auto messageFromId = channelPost ? 0 : _session->userId();
|
const auto messageFromId = channelPost ? 0 : _session->userId();
|
||||||
const auto messagePostAuthor = channelPost
|
const auto messagePostAuthor = channelPost
|
||||||
? App::peerName(_session->user())
|
? App::peerName(_session->user())
|
||||||
|
@ -4586,7 +4600,7 @@ void ApiWrap::sendSharedContact(
|
||||||
MTPMessageFwdHeader(),
|
MTPMessageFwdHeader(),
|
||||||
MTPint(),
|
MTPint(),
|
||||||
MTP_int(action.replyTo),
|
MTP_int(action.replyTo),
|
||||||
MTP_int(base::unixtime::now()),
|
MTP_int(HistoryItem::NewMessageDate(action.options.scheduled)),
|
||||||
MTP_string(),
|
MTP_string(),
|
||||||
MTP_messageMediaContact(
|
MTP_messageMediaContact(
|
||||||
MTP_string(phone),
|
MTP_string(phone),
|
||||||
|
@ -4907,7 +4921,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
HistoryItem *lastMessage = nullptr;
|
HistoryItem *lastMessage = nullptr;
|
||||||
|
|
||||||
while (TextUtilities::CutPart(sending, left, MaxMessageSize)) {
|
while (TextUtilities::CutPart(sending, left, MaxMessageSize)) {
|
||||||
auto newId = FullMsgId(peerToChannel(peer->id), clientMsgId());
|
auto newId = FullMsgId(
|
||||||
|
peerToChannel(peer->id),
|
||||||
|
session().data().nextLocalMessageId());
|
||||||
auto randomId = rand_value<uint64>();
|
auto randomId = rand_value<uint64>();
|
||||||
|
|
||||||
TextUtilities::Trim(sending);
|
TextUtilities::Trim(sending);
|
||||||
|
@ -4963,6 +4979,12 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
auto messagePostAuthor = channelPost
|
auto messagePostAuthor = channelPost
|
||||||
? App::peerName(_session->user())
|
? App::peerName(_session->user())
|
||||||
: QString();
|
: QString();
|
||||||
|
if (action.options.scheduled) {
|
||||||
|
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||||
|
sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
|
||||||
|
} else {
|
||||||
|
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||||
|
}
|
||||||
lastMessage = history->addNewMessage(
|
lastMessage = history->addNewMessage(
|
||||||
MTP_message(
|
MTP_message(
|
||||||
MTP_flags(flags),
|
MTP_flags(flags),
|
||||||
|
@ -4972,7 +4994,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
MTPMessageFwdHeader(),
|
MTPMessageFwdHeader(),
|
||||||
MTPint(),
|
MTPint(),
|
||||||
MTP_int(action.replyTo),
|
MTP_int(action.replyTo),
|
||||||
MTP_int(base::unixtime::now()),
|
MTP_int(
|
||||||
|
HistoryItem::NewMessageDate(action.options.scheduled)),
|
||||||
msgText,
|
msgText,
|
||||||
media,
|
media,
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
|
@ -4993,7 +5016,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
sentEntities,
|
sentEntities,
|
||||||
MTP_int(0) // schedule_date
|
MTP_int(action.options.scheduled)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
applyUpdates(result, randomId);
|
applyUpdates(result, randomId);
|
||||||
history->clearSentDraftText(QString());
|
history->clearSentDraftText(QString());
|
||||||
|
@ -5053,7 +5076,9 @@ void ApiWrap::sendInlineResult(
|
||||||
|
|
||||||
const auto history = action.history;
|
const auto history = action.history;
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
const auto newId = FullMsgId(peerToChannel(peer->id), clientMsgId());
|
const auto newId = FullMsgId(
|
||||||
|
peerToChannel(peer->id),
|
||||||
|
session().data().nextLocalMessageId());
|
||||||
const auto randomId = rand_value<uint64>();
|
const auto randomId = rand_value<uint64>();
|
||||||
|
|
||||||
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
|
||||||
|
@ -5081,14 +5106,17 @@ void ApiWrap::sendInlineResult(
|
||||||
if (bot) {
|
if (bot) {
|
||||||
flags |= MTPDmessage::Flag::f_via_bot_id;
|
flags |= MTPDmessage::Flag::f_via_bot_id;
|
||||||
}
|
}
|
||||||
|
if (action.options.scheduled) {
|
||||||
|
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||||
|
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_schedule_date;
|
||||||
|
} else {
|
||||||
|
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||||
|
}
|
||||||
|
|
||||||
auto messageFromId = channelPost ? 0 : _session->userId();
|
const auto messageFromId = channelPost ? 0 : _session->userId();
|
||||||
auto messagePostAuthor = channelPost
|
const auto messagePostAuthor = channelPost
|
||||||
? App::peerName(_session->user())
|
? App::peerName(_session->user())
|
||||||
: QString();
|
: QString();
|
||||||
MTPint messageDate = MTP_int(base::unixtime::now());
|
|
||||||
UserId messageViaBotId = bot ? peerToUser(bot->id) : 0;
|
|
||||||
MsgId messageId = newId.msg;
|
|
||||||
|
|
||||||
_session->data().registerMessageRandomId(randomId, newId);
|
_session->data().registerMessageRandomId(randomId, newId);
|
||||||
|
|
||||||
|
@ -5096,10 +5124,10 @@ void ApiWrap::sendInlineResult(
|
||||||
history,
|
history,
|
||||||
flags,
|
flags,
|
||||||
clientFlags,
|
clientFlags,
|
||||||
messageId,
|
newId.msg,
|
||||||
messageFromId,
|
messageFromId,
|
||||||
messageDate,
|
MTP_int(HistoryItem::NewMessageDate(action.options.scheduled)),
|
||||||
messageViaBotId,
|
bot ? peerToUser(bot->id) : 0,
|
||||||
action.replyTo,
|
action.replyTo,
|
||||||
messagePostAuthor);
|
messagePostAuthor);
|
||||||
|
|
||||||
|
@ -5113,7 +5141,7 @@ void ApiWrap::sendInlineResult(
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
MTP_long(data->getQueryId()),
|
MTP_long(data->getQueryId()),
|
||||||
MTP_string(data->getId()),
|
MTP_string(data->getId()),
|
||||||
MTP_int(0) // schedule_date
|
MTP_int(action.options.scheduled)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
applyUpdates(result, randomId);
|
applyUpdates(result, randomId);
|
||||||
history->clearSentDraftText(QString());
|
history->clearSentDraftText(QString());
|
||||||
|
@ -5236,6 +5264,9 @@ void ApiWrap::sendMediaWithRandomId(
|
||||||
: MTPmessages_SendMedia::Flag(0))
|
: MTPmessages_SendMedia::Flag(0))
|
||||||
| (!sentEntities.v.isEmpty()
|
| (!sentEntities.v.isEmpty()
|
||||||
? MTPmessages_SendMedia::Flag::f_entities
|
? MTPmessages_SendMedia::Flag::f_entities
|
||||||
|
: MTPmessages_SendMedia::Flag(0))
|
||||||
|
| (options.scheduled
|
||||||
|
? MTPmessages_SendMedia::Flag::f_schedule_date
|
||||||
: MTPmessages_SendMedia::Flag(0));
|
: MTPmessages_SendMedia::Flag(0));
|
||||||
|
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
|
@ -5249,7 +5280,7 @@ void ApiWrap::sendMediaWithRandomId(
|
||||||
MTP_long(randomId),
|
MTP_long(randomId),
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
sentEntities,
|
sentEntities,
|
||||||
MTP_int(0) // schedule_date
|
MTP_int(options.scheduled)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
applyUpdates(result);
|
applyUpdates(result);
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
|
@ -5330,6 +5361,9 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
||||||
: MTPmessages_SendMultiMedia::Flag(0))
|
: MTPmessages_SendMultiMedia::Flag(0))
|
||||||
| (album->options.silent
|
| (album->options.silent
|
||||||
? MTPmessages_SendMultiMedia::Flag::f_silent
|
? MTPmessages_SendMultiMedia::Flag::f_silent
|
||||||
|
: MTPmessages_SendMultiMedia::Flag(0))
|
||||||
|
| (album->options.scheduled
|
||||||
|
? MTPmessages_SendMultiMedia::Flag::f_schedule_date
|
||||||
: MTPmessages_SendMultiMedia::Flag(0));
|
: MTPmessages_SendMultiMedia::Flag(0));
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
history->sendRequestId = request(MTPmessages_SendMultiMedia(
|
history->sendRequestId = request(MTPmessages_SendMultiMedia(
|
||||||
|
@ -5337,7 +5371,7 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
||||||
peer->input,
|
peer->input,
|
||||||
MTP_int(replyTo),
|
MTP_int(replyTo),
|
||||||
MTP_vector<MTPInputSingleMedia>(medias),
|
MTP_vector<MTPInputSingleMedia>(medias),
|
||||||
MTP_int(0) // schedule_date
|
MTP_int(album->options.scheduled)
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
_sendingAlbums.remove(groupId);
|
_sendingAlbums.remove(groupId);
|
||||||
applyUpdates(result);
|
applyUpdates(result);
|
||||||
|
@ -5360,10 +5394,7 @@ FileLoadTo ApiWrap::fileLoadTaskOptions(const SendAction &action) const {
|
||||||
if (_session->data().notifySilentPosts(peer)) {
|
if (_session->data().notifySilentPosts(peer)) {
|
||||||
options.silent = true;
|
options.silent = true;
|
||||||
}
|
}
|
||||||
return FileLoadTo(
|
return FileLoadTo(peer->id, action.options, action.replyTo);
|
||||||
peer->id,
|
|
||||||
action.options,
|
|
||||||
action.replyTo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::requestSupportContact(FnMut<void(const MTPUser &)> callback) {
|
void ApiWrap::requestSupportContact(FnMut<void(const MTPUser &)> callback) {
|
||||||
|
@ -5387,7 +5418,9 @@ void ApiWrap::uploadPeerPhoto(not_null<PeerData*> peer, QImage &&image) {
|
||||||
peer = peer->migrateToOrMe();
|
peer = peer->migrateToOrMe();
|
||||||
const auto ready = PreparePeerPhoto(peer->id, std::move(image));
|
const auto ready = PreparePeerPhoto(peer->id, std::move(image));
|
||||||
|
|
||||||
const auto fakeId = FullMsgId(peerToChannel(peer->id), clientMsgId());
|
const auto fakeId = FullMsgId(
|
||||||
|
peerToChannel(peer->id),
|
||||||
|
session().data().nextLocalMessageId());
|
||||||
const auto already = ranges::find(
|
const auto already = ranges::find(
|
||||||
_peerPhotoUploads,
|
_peerPhotoUploads,
|
||||||
peer,
|
peer,
|
||||||
|
@ -5817,6 +5850,9 @@ void ApiWrap::createPoll(
|
||||||
if (silentPost) {
|
if (silentPost) {
|
||||||
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
|
||||||
}
|
}
|
||||||
|
if (action.options.scheduled) {
|
||||||
|
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
|
||||||
|
}
|
||||||
|
|
||||||
const auto replyTo = action.replyTo;
|
const auto replyTo = action.replyTo;
|
||||||
history->sendRequestId = request(MTPmessages_SendMedia(
|
history->sendRequestId = request(MTPmessages_SendMedia(
|
||||||
|
@ -5828,7 +5864,7 @@ void ApiWrap::createPoll(
|
||||||
MTP_long(rand_value<uint64>()),
|
MTP_long(rand_value<uint64>()),
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
MTPVector<MTPMessageEntity>(),
|
MTPVector<MTPMessageEntity>(),
|
||||||
MTP_int(0) // schedule_date
|
MTP_int(action.options.scheduled)
|
||||||
)).done([=, done = std::move(done)](const MTPUpdates &result) mutable {
|
)).done([=, done = std::move(done)](const MTPUpdates &result) mutable {
|
||||||
applyUpdates(result);
|
applyUpdates(result);
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -771,8 +771,14 @@ void DeleteMessagesBox::deleteAndClear() {
|
||||||
if (const auto item = _session->data().message(itemId)) {
|
if (const auto item = _session->data().message(itemId)) {
|
||||||
const auto history = item->history();
|
const auto history = item->history();
|
||||||
if (item->isScheduled()) {
|
if (item->isScheduled()) {
|
||||||
scheduledIdsByPeer[history->peer].push_back(MTP_int(
|
const auto wasOnServer = !item->isSending()
|
||||||
_session->data().scheduledMessages().lookupId(item)));
|
&& !item->hasFailed();
|
||||||
|
if (wasOnServer) {
|
||||||
|
scheduledIdsByPeer[history->peer].push_back(MTP_int(
|
||||||
|
_session->data().scheduledMessages().lookupId(item)));
|
||||||
|
} else {
|
||||||
|
_session->data().scheduledMessages().removeSending(item);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto wasOnServer = IsServerMsgId(item->id);
|
const auto wasOnServer = IsServerMsgId(item->id);
|
||||||
|
|
|
@ -137,6 +137,49 @@ void ScheduledMessages::apply(
|
||||||
_updates.fire_copy(history);
|
_updates.fire_copy(history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScheduledMessages::apply(
|
||||||
|
const MTPDupdateMessageID &update,
|
||||||
|
not_null<HistoryItem*> local) {
|
||||||
|
const auto id = update.vid().v;
|
||||||
|
const auto i = _data.find(local->history());
|
||||||
|
Assert(i != end(_data));
|
||||||
|
auto &list = i->second;
|
||||||
|
const auto j = list.itemById.find(id);
|
||||||
|
if (j != end(list.itemById)) {
|
||||||
|
local->destroy();
|
||||||
|
} else {
|
||||||
|
Assert(!list.itemById.contains(local->id));
|
||||||
|
Assert(!list.idByItem.contains(local));
|
||||||
|
local->setRealId(local->history()->nextNonHistoryEntryId());
|
||||||
|
list.idByItem.emplace(local, id);
|
||||||
|
list.itemById.emplace(id, local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledMessages::appendSending(not_null<HistoryItem*> item) {
|
||||||
|
Expects(item->isSending());
|
||||||
|
Expects(item->isScheduled());
|
||||||
|
|
||||||
|
const auto history = item->history();
|
||||||
|
auto &list = _data[history];
|
||||||
|
list.items.emplace_back(item);
|
||||||
|
sort(list);
|
||||||
|
_updates.fire_copy(history);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledMessages::removeSending(not_null<HistoryItem*> item) {
|
||||||
|
Expects(item->isSending() || item->hasFailed());
|
||||||
|
Expects(item->isScheduled());
|
||||||
|
|
||||||
|
const auto history = item->history();
|
||||||
|
auto &list = _data[history];
|
||||||
|
Assert(!list.itemById.contains(item->id));
|
||||||
|
Assert(!list.idByItem.contains(item));
|
||||||
|
list.items.erase(
|
||||||
|
ranges::remove(list.items, item.get(), &OwnedItem::get),
|
||||||
|
end(list.items));
|
||||||
|
}
|
||||||
|
|
||||||
rpl::producer<> ScheduledMessages::updates(not_null<History*> history) {
|
rpl::producer<> ScheduledMessages::updates(not_null<History*> history) {
|
||||||
request(history);
|
request(history);
|
||||||
|
|
||||||
|
@ -175,10 +218,12 @@ void ScheduledMessages::request(not_null<History*> history) {
|
||||||
if (request.requestId) {
|
if (request.requestId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto i = _data.find(history);
|
||||||
|
const auto hash = (i != end(_data)) ? countListHash(i->second) : 0;
|
||||||
request.requestId = _session->api().request(
|
request.requestId = _session->api().request(
|
||||||
MTPmessages_GetScheduledHistory(
|
MTPmessages_GetScheduledHistory(
|
||||||
history->peer->input,
|
history->peer->input,
|
||||||
MTP_int(request.hash))
|
MTP_int(hash))
|
||||||
).done([=](const MTPmessages_Messages &result) {
|
).done([=](const MTPmessages_Messages &result) {
|
||||||
parse(history, result);
|
parse(history, result);
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
|
@ -197,14 +242,33 @@ void ScheduledMessages::parse(
|
||||||
}, [&](const auto &data) {
|
}, [&](const auto &data) {
|
||||||
_session->data().processUsers(data.vusers());
|
_session->data().processUsers(data.vusers());
|
||||||
_session->data().processChats(data.vchats());
|
_session->data().processChats(data.vchats());
|
||||||
|
|
||||||
const auto &messages = data.vmessages().v;
|
const auto &messages = data.vmessages().v;
|
||||||
if (messages.isEmpty()) {
|
if (messages.isEmpty()) {
|
||||||
|
if (element != end(_data)) {
|
||||||
|
_data.erase(element);
|
||||||
|
element = end(_data);
|
||||||
|
_updates.fire_copy(history);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
element = _data.emplace(history, List()).first;
|
element = _data.emplace(history, List()).first;
|
||||||
|
auto received = base::flat_set<not_null<HistoryItem*>>();
|
||||||
auto &list = element->second;
|
auto &list = element->second;
|
||||||
for (const auto &message : messages) {
|
for (const auto &message : messages) {
|
||||||
append(history, list, message);
|
if (const auto item = append(history, list, message)) {
|
||||||
|
received.emplace(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto clear = base::flat_set<not_null<HistoryItem*>>();
|
||||||
|
for (const auto &owned : list.items) {
|
||||||
|
const auto item = owned.get();
|
||||||
|
if (!item->isSending() && !received.contains(item)) {
|
||||||
|
clear.emplace(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto item : clear) {
|
||||||
|
item->destroy();
|
||||||
}
|
}
|
||||||
if (!list.items.empty()) {
|
if (!list.items.empty()) {
|
||||||
sort(list);
|
sort(list);
|
||||||
|
@ -214,24 +278,21 @@ void ScheduledMessages::parse(
|
||||||
}
|
}
|
||||||
_updates.fire_copy(history);
|
_updates.fire_copy(history);
|
||||||
});
|
});
|
||||||
|
if (!request.requestId) {
|
||||||
request.hash = (element != end(_data))
|
|
||||||
? countListHash(element->second)
|
|
||||||
: 0;
|
|
||||||
if (!request.requestId && !request.hash) {
|
|
||||||
_requests.remove(history);
|
_requests.remove(history);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduledMessages::append(
|
HistoryItem *ScheduledMessages::append(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
List &list,
|
List &list,
|
||||||
const MTPMessage &message) {
|
const MTPMessage &message) {
|
||||||
const auto id = message.match([&](const auto &data) {
|
const auto id = message.match([&](const auto &data) {
|
||||||
return data.vid().v;
|
return data.vid().v;
|
||||||
});
|
});
|
||||||
if (list.itemById.find(id) != end(list.itemById)) {
|
const auto i = list.itemById.find(id);
|
||||||
return;
|
if (i != end(list.itemById)) {
|
||||||
|
return i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto item = _session->data().addNewMessage(
|
const auto item = _session->data().addNewMessage(
|
||||||
|
@ -240,11 +301,12 @@ void ScheduledMessages::append(
|
||||||
NewMessageType::Existing);
|
NewMessageType::Existing);
|
||||||
if (!item || item->history() != history) {
|
if (!item || item->history() != history) {
|
||||||
LOG(("API Error: Bad data received in scheduled messages."));
|
LOG(("API Error: Bad data received in scheduled messages."));
|
||||||
return;
|
return nullptr;
|
||||||
}
|
}
|
||||||
list.items.emplace_back(item);
|
list.items.emplace_back(item);
|
||||||
list.itemById.emplace(id, item);
|
list.itemById.emplace(id, item);
|
||||||
list.idByItem.emplace(item, id);
|
list.idByItem.emplace(item, id);
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduledMessages::sort(List &list) {
|
void ScheduledMessages::sort(List &list) {
|
||||||
|
@ -277,7 +339,12 @@ int32 ScheduledMessages::countListHash(const List &list) const {
|
||||||
using namespace Api;
|
using namespace Api;
|
||||||
|
|
||||||
auto hash = HashInit();
|
auto hash = HashInit();
|
||||||
for (const auto &item : list.items | ranges::view::reverse) {
|
auto &&serverside = ranges::view::all(
|
||||||
|
list.items
|
||||||
|
) | ranges::view::filter([](const OwnedItem &item) {
|
||||||
|
return !item->isSending() && !item->hasFailed();
|
||||||
|
}) | ranges::view::reverse;
|
||||||
|
for (const auto &item : serverside) {
|
||||||
const auto j = list.idByItem.find(item.get());
|
const auto j = list.idByItem.find(item.get());
|
||||||
HashUpdate(hash, j->second);
|
HashUpdate(hash, j->second);
|
||||||
if (const auto edited = item->Get<HistoryMessageEdited>()) {
|
if (const auto edited = item->Get<HistoryMessageEdited>()) {
|
||||||
|
|
|
@ -32,6 +32,12 @@ public:
|
||||||
|
|
||||||
void apply(const MTPDupdateNewScheduledMessage &update);
|
void apply(const MTPDupdateNewScheduledMessage &update);
|
||||||
void apply(const MTPDupdateDeleteScheduledMessages &update);
|
void apply(const MTPDupdateDeleteScheduledMessages &update);
|
||||||
|
void apply(
|
||||||
|
const MTPDupdateMessageID &update,
|
||||||
|
not_null<HistoryItem*> local);
|
||||||
|
|
||||||
|
void appendSending(not_null<HistoryItem*> item);
|
||||||
|
void removeSending(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> updates(not_null<History*> history);
|
[[nodiscard]] rpl::producer<> updates(not_null<History*> history);
|
||||||
[[nodiscard]] Data::MessagesSlice list(not_null<History*> history);
|
[[nodiscard]] Data::MessagesSlice list(not_null<History*> history);
|
||||||
|
@ -44,7 +50,6 @@ private:
|
||||||
base::flat_map<not_null<HistoryItem*>, MsgId> idByItem;
|
base::flat_map<not_null<HistoryItem*>, MsgId> idByItem;
|
||||||
};
|
};
|
||||||
struct Request {
|
struct Request {
|
||||||
int32 hash = 0;
|
|
||||||
mtpRequestId requestId = 0;
|
mtpRequestId requestId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,7 +57,7 @@ private:
|
||||||
void parse(
|
void parse(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
const MTPmessages_Messages &list);
|
const MTPmessages_Messages &list);
|
||||||
void append(
|
HistoryItem *append(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
List &list,
|
List &list,
|
||||||
const MTPMessage &message);
|
const MTPMessage &message);
|
||||||
|
|
|
@ -1844,6 +1844,12 @@ void Session::destroyMessage(not_null<HistoryItem*> item) {
|
||||||
list->erase(item->id);
|
list->erase(item->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MsgId Session::nextLocalMessageId() {
|
||||||
|
Expects(_localMessageIdCounter < EndClientMsgId);
|
||||||
|
|
||||||
|
return _localMessageIdCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
HistoryItem *Session::message(ChannelId channelId, MsgId itemId) const {
|
HistoryItem *Session::message(ChannelId channelId, MsgId itemId) const {
|
||||||
if (!itemId) {
|
if (!itemId) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -3627,13 +3633,14 @@ void Session::insertCheckedServiceNotification(
|
||||||
const auto flags = MTPDmessage::Flag::f_entities
|
const auto flags = MTPDmessage::Flag::f_entities
|
||||||
| MTPDmessage::Flag::f_from_id
|
| MTPDmessage::Flag::f_from_id
|
||||||
| MTPDmessage::Flag::f_media;
|
| MTPDmessage::Flag::f_media;
|
||||||
const auto clientFlags = MTPDmessage_ClientFlag::f_clientside_unread;
|
const auto clientFlags = MTPDmessage_ClientFlag::f_clientside_unread
|
||||||
|
| MTPDmessage_ClientFlag::f_local_history_entry;
|
||||||
auto sending = TextWithEntities(), left = message;
|
auto sending = TextWithEntities(), left = message;
|
||||||
while (TextUtilities::CutPart(sending, left, MaxMessageSize)) {
|
while (TextUtilities::CutPart(sending, left, MaxMessageSize)) {
|
||||||
addNewMessage(
|
addNewMessage(
|
||||||
MTP_message(
|
MTP_message(
|
||||||
MTP_flags(flags),
|
MTP_flags(flags),
|
||||||
MTP_int(clientMsgId()),
|
MTP_int(nextLocalMessageId()),
|
||||||
MTP_int(peerToUser(PeerData::kServiceNotificationsId)),
|
MTP_int(peerToUser(PeerData::kServiceNotificationsId)),
|
||||||
MTP_peerUser(MTP_int(_session->userId())),
|
MTP_peerUser(MTP_int(_session->userId())),
|
||||||
MTPMessageFwdHeader(),
|
MTPMessageFwdHeader(),
|
||||||
|
|
|
@ -387,6 +387,7 @@ public:
|
||||||
ChannelId channelId,
|
ChannelId channelId,
|
||||||
const QVector<MTPint> &data);
|
const QVector<MTPint> &data);
|
||||||
|
|
||||||
|
[[nodiscard]] MsgId nextLocalMessageId();
|
||||||
[[nodiscard]] HistoryItem *message(
|
[[nodiscard]] HistoryItem *message(
|
||||||
ChannelId channelId,
|
ChannelId channelId,
|
||||||
MsgId itemId) const;
|
MsgId itemId) const;
|
||||||
|
@ -877,6 +878,7 @@ private:
|
||||||
Dialogs::IndexedList _contactsList;
|
Dialogs::IndexedList _contactsList;
|
||||||
Dialogs::IndexedList _contactsNoChatsList;
|
Dialogs::IndexedList _contactsNoChatsList;
|
||||||
|
|
||||||
|
MsgId _localMessageIdCounter = StartClientMsgId;
|
||||||
Messages _messages;
|
Messages _messages;
|
||||||
std::map<ChannelId, Messages> _channelMessages;
|
std::map<ChannelId, Messages> _channelMessages;
|
||||||
std::map<
|
std::map<
|
||||||
|
|
|
@ -415,12 +415,6 @@ inline bool operator!=(const AudioMsgId &a, const AudioMsgId &b) {
|
||||||
return !(a == b);
|
return !(a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline MsgId clientMsgId() {
|
|
||||||
static MsgId CurrentClientMsgId = StartClientMsgId;
|
|
||||||
Assert(CurrentClientMsgId < EndClientMsgId);
|
|
||||||
return CurrentClientMsgId++;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MessageCursor {
|
struct MessageCursor {
|
||||||
MessageCursor() = default;
|
MessageCursor() = default;
|
||||||
MessageCursor(int position, int anchor, int scroll)
|
MessageCursor(int position, int anchor, int scroll)
|
||||||
|
|
|
@ -16,6 +16,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
|
#include "data/data_channel_admins.h"
|
||||||
|
#include "data/data_scheduled_messages.h"
|
||||||
|
#include "data/data_folder.h"
|
||||||
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_chat.h"
|
||||||
|
#include "data/data_user.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
@ -29,12 +36,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "storage/storage_shared_media.h"
|
#include "storage/storage_shared_media.h"
|
||||||
//#include "storage/storage_feed_messages.h" // #feed
|
//#include "storage/storage_feed_messages.h" // #feed
|
||||||
#include "support/support_helper.h"
|
#include "support/support_helper.h"
|
||||||
#include "data/data_channel_admins.h"
|
|
||||||
#include "data/data_folder.h"
|
|
||||||
#include "data/data_photo.h"
|
|
||||||
#include "data/data_channel.h"
|
|
||||||
#include "data/data_chat.h"
|
|
||||||
#include "data/data_user.h"
|
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/text_options.h"
|
#include "ui/text_options.h"
|
||||||
#include "core/crash_reports.h"
|
#include "core/crash_reports.h"
|
||||||
|
@ -622,51 +623,50 @@ HistoryItem *History::addNewMessage(
|
||||||
const MTPMessage &msg,
|
const MTPMessage &msg,
|
||||||
MTPDmessage_ClientFlags clientFlags,
|
MTPDmessage_ClientFlags clientFlags,
|
||||||
NewMessageType type) {
|
NewMessageType type) {
|
||||||
if (type == NewMessageType::Existing) {
|
const auto detachExistingItem = (type == NewMessageType::Unread);
|
||||||
return addToHistory(msg, clientFlags);
|
const auto item = createItem(msg, clientFlags, detachExistingItem);
|
||||||
}
|
if (!item) {
|
||||||
if (!loadedAtBottom() || peer->migrateTo()) {
|
|
||||||
if (const auto item = addToHistory(msg, clientFlags)) {
|
|
||||||
setLastMessage(item);
|
|
||||||
if (type == NewMessageType::Unread) {
|
|
||||||
newItemAdded(item);
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
if (type == NewMessageType::Existing || item->mainView()) {
|
||||||
return addNewToLastBlock(msg, clientFlags, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryItem *History::addNewToLastBlock(
|
|
||||||
const MTPMessage &msg,
|
|
||||||
MTPDmessage_ClientFlags clientFlags,
|
|
||||||
NewMessageType type) {
|
|
||||||
Expects(type != NewMessageType::Existing);
|
|
||||||
|
|
||||||
const auto detachExistingItem = (type != NewMessageType::Last);
|
|
||||||
const auto item = createItem(msg, clientFlags, detachExistingItem);
|
|
||||||
if (!item || item->mainView()) {
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
const auto newUnreadMessage = (type == NewMessageType::Unread);
|
const auto unread = (type == NewMessageType::Unread);
|
||||||
if (newUnreadMessage) {
|
if (unread && item->isHistoryEntry()) {
|
||||||
applyMessageChanges(item, msg);
|
applyMessageChanges(item, msg);
|
||||||
}
|
}
|
||||||
const auto result = addNewItem(item, newUnreadMessage);
|
return addNewItem(item, unread);
|
||||||
checkForLoadedAtTop(result);
|
}
|
||||||
if (type == NewMessageType::Last) {
|
|
||||||
// When we add just one last item, like we do while loading dialogs,
|
not_null<HistoryItem*> History::addNewItem(
|
||||||
// we want to remove a single added grouped media, otherwise it will
|
not_null<HistoryItem*> item,
|
||||||
// jump once we open the message history (first we show only that
|
bool unread) {
|
||||||
// media, then we load the rest of the group and show the group).
|
if (item->isScheduled()) {
|
||||||
//
|
session().data().scheduledMessages().appendSending(item);
|
||||||
// That way when we open the message history we show nothing until a
|
return item;
|
||||||
// whole history part is loaded, it certainly will contain the group.
|
} else if (!item->isHistoryEntry()) {
|
||||||
removeOrphanMediaGroupPart();
|
return item;
|
||||||
}
|
}
|
||||||
return result;
|
if (!loadedAtBottom() || peer->migrateTo()) {
|
||||||
|
setLastMessage(item);
|
||||||
|
if (unread) {
|
||||||
|
newItemAdded(item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addNewToBack(item, unread);
|
||||||
|
checkForLoadedAtTop(item);
|
||||||
|
if (!unread) {
|
||||||
|
// When we add just one last item, like we do while loading dialogs,
|
||||||
|
// we want to remove a single added grouped media, otherwise it will
|
||||||
|
// jump once we open the message history (first we show only that
|
||||||
|
// media, then we load the rest of the group and show the group).
|
||||||
|
//
|
||||||
|
// That way when we open the message history we show nothing until a
|
||||||
|
// whole history part is loaded, it certainly will contain the group.
|
||||||
|
removeOrphanMediaGroupPart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::checkForLoadedAtTop(not_null<HistoryItem*> added) {
|
void History::checkForLoadedAtTop(not_null<HistoryItem*> added) {
|
||||||
|
@ -896,7 +896,7 @@ void History::addUnreadMentionsSlice(const MTPmessages_Messages &result) {
|
||||||
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::UnreadMentionsChanged);
|
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::UnreadMentionsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<HistoryItem*> History::addNewItem(
|
not_null<HistoryItem*> History::addNewToBack(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
bool unread) {
|
bool unread) {
|
||||||
Expects(!isBuildingFrontBlock());
|
Expects(!isBuildingFrontBlock());
|
||||||
|
@ -2866,7 +2866,7 @@ void History::insertLocalMessage(not_null<HistoryItem*> item) {
|
||||||
Expects(item->mainView() == nullptr);
|
Expects(item->mainView() == nullptr);
|
||||||
|
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
addNewItem(item, false);
|
addNewToBack(item, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -387,11 +387,6 @@ private:
|
||||||
// helper method for countScrollState(int top)
|
// helper method for countScrollState(int top)
|
||||||
void countScrollTopItem(int top);
|
void countScrollTopItem(int top);
|
||||||
|
|
||||||
HistoryItem *addNewToLastBlock(
|
|
||||||
const MTPMessage &msg,
|
|
||||||
MTPDmessage_ClientFlags clientFlags,
|
|
||||||
NewMessageType type);
|
|
||||||
|
|
||||||
// this method just removes a block from the blocks list
|
// this method just removes a block from the blocks list
|
||||||
// when the last item from this block was detached and
|
// when the last item from this block was detached and
|
||||||
// calls the required previousItemChanged()
|
// calls the required previousItemChanged()
|
||||||
|
@ -401,6 +396,9 @@ private:
|
||||||
not_null<HistoryItem*> addNewItem(
|
not_null<HistoryItem*> addNewItem(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
bool unread);
|
bool unread);
|
||||||
|
not_null<HistoryItem*> addNewToBack(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
bool unread);
|
||||||
not_null<HistoryItem*> addNewInTheMiddle(
|
not_null<HistoryItem*> addNewInTheMiddle(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
int blockIndex,
|
int blockIndex,
|
||||||
|
|
|
@ -187,6 +187,11 @@ TimeId HistoryItem::date() const {
|
||||||
return _date;
|
return _date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimeId HistoryItem::NewMessageDate(TimeId scheduled) {
|
||||||
|
const auto now = base::unixtime::now();
|
||||||
|
return scheduled ? std::max(scheduled, now + 60) : now;
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryItem::finishEdition(int oldKeyboardTop) {
|
void HistoryItem::finishEdition(int oldKeyboardTop) {
|
||||||
_history->owner().requestItemViewRefresh(this);
|
_history->owner().requestItemViewRefresh(this);
|
||||||
invalidateChatListEntry();
|
invalidateChatListEntry();
|
||||||
|
|
|
@ -86,7 +86,8 @@ public:
|
||||||
UserData *getMessageBot() const;
|
UserData *getMessageBot() const;
|
||||||
|
|
||||||
[[nodiscard]] bool isHistoryEntry() const {
|
[[nodiscard]] bool isHistoryEntry() const {
|
||||||
return (id < ServerMaxMsgId);
|
return IsServerMsgId(id)
|
||||||
|
|| (_clientFlags & MTPDmessage_ClientFlag::f_local_history_entry);
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool isFromScheduled() const {
|
[[nodiscard]] bool isFromScheduled() const {
|
||||||
return isHistoryEntry()
|
return isHistoryEntry()
|
||||||
|
@ -190,13 +191,13 @@ public:
|
||||||
return _clientFlags & MTPDmessage_ClientFlag::f_failed;
|
return _clientFlags & MTPDmessage_ClientFlag::f_failed;
|
||||||
}
|
}
|
||||||
void sendFailed();
|
void sendFailed();
|
||||||
virtual int viewsCount() const {
|
[[nodiscard]] virtual int viewsCount() const {
|
||||||
return hasViews() ? 1 : -1;
|
return hasViews() ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool needCheck() const;
|
[[nodiscard]] virtual bool needCheck() const;
|
||||||
|
|
||||||
virtual bool serviceMsg() const {
|
[[nodiscard]] virtual bool serviceMsg() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
virtual void applyEdition(const MTPDmessage &message) {
|
virtual void applyEdition(const MTPDmessage &message) {
|
||||||
|
@ -218,14 +219,14 @@ public:
|
||||||
virtual void addToUnreadMentions(UnreadMentionType type);
|
virtual void addToUnreadMentions(UnreadMentionType type);
|
||||||
virtual void eraseFromUnreadMentions() {
|
virtual void eraseFromUnreadMentions() {
|
||||||
}
|
}
|
||||||
virtual Storage::SharedMediaTypesMask sharedMediaTypes() const = 0;
|
[[nodiscard]] virtual Storage::SharedMediaTypesMask sharedMediaTypes() const = 0;
|
||||||
|
|
||||||
void indexAsNewItem();
|
void indexAsNewItem();
|
||||||
|
|
||||||
virtual QString notificationHeader() const {
|
[[nodiscard]] virtual QString notificationHeader() const {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
virtual QString notificationText() const;
|
[[nodiscard]] virtual QString notificationText() const;
|
||||||
|
|
||||||
enum class DrawInDialog {
|
enum class DrawInDialog {
|
||||||
Normal,
|
Normal,
|
||||||
|
@ -234,15 +235,15 @@ public:
|
||||||
|
|
||||||
// Returns text with link-start and link-end commands for service-color highlighting.
|
// Returns text with link-start and link-end commands for service-color highlighting.
|
||||||
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
|
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
|
||||||
virtual QString inDialogsText(DrawInDialog way) const;
|
[[nodiscard]] virtual QString inDialogsText(DrawInDialog way) const;
|
||||||
virtual QString inReplyText() const {
|
[[nodiscard]] virtual QString inReplyText() const {
|
||||||
return inDialogsText(DrawInDialog::WithoutSender);
|
return inDialogsText(DrawInDialog::WithoutSender);
|
||||||
}
|
}
|
||||||
virtual Ui::Text::IsolatedEmoji isolatedEmoji() const;
|
[[nodiscard]] virtual Ui::Text::IsolatedEmoji isolatedEmoji() const;
|
||||||
virtual TextWithEntities originalText() const {
|
[[nodiscard]] virtual TextWithEntities originalText() const {
|
||||||
return TextWithEntities();
|
return TextWithEntities();
|
||||||
}
|
}
|
||||||
virtual TextForMimeData clipboardText() const {
|
[[nodiscard]] virtual TextForMimeData clipboardText() const {
|
||||||
return TextForMimeData();
|
return TextForMimeData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,81 +260,83 @@ public:
|
||||||
const HistoryItem *&cacheFor,
|
const HistoryItem *&cacheFor,
|
||||||
Ui::Text::String &cache) const;
|
Ui::Text::String &cache) const;
|
||||||
|
|
||||||
bool emptyText() const {
|
[[nodiscard]] bool emptyText() const {
|
||||||
return _text.isEmpty();
|
return _text.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPinned() const;
|
[[nodiscard]] bool isPinned() const;
|
||||||
bool canPin() const;
|
[[nodiscard]] bool canPin() const;
|
||||||
bool canStopPoll() const;
|
[[nodiscard]] bool canStopPoll() const;
|
||||||
virtual bool allowsSendNow() const;
|
[[nodiscard]] virtual bool allowsSendNow() const;
|
||||||
virtual bool allowsForward() const;
|
[[nodiscard]] virtual bool allowsForward() const;
|
||||||
virtual bool allowsEdit(TimeId now) const;
|
[[nodiscard]] virtual bool allowsEdit(TimeId now) const;
|
||||||
bool canDelete() const;
|
[[nodiscard]] bool canDelete() const;
|
||||||
bool canDeleteForEveryone(TimeId now) const;
|
[[nodiscard]] bool canDeleteForEveryone(TimeId now) const;
|
||||||
bool suggestReport() const;
|
[[nodiscard]] bool suggestReport() const;
|
||||||
bool suggestBanReport() const;
|
[[nodiscard]] bool suggestBanReport() const;
|
||||||
bool suggestDeleteAllReport() const;
|
[[nodiscard]] bool suggestDeleteAllReport() const;
|
||||||
|
|
||||||
bool hasDirectLink() const;
|
[[nodiscard]] bool hasDirectLink() const;
|
||||||
|
|
||||||
MsgId id;
|
[[nodiscard]] ChannelId channelId() const;
|
||||||
|
[[nodiscard]] FullMsgId fullId() const {
|
||||||
ChannelId channelId() const;
|
|
||||||
FullMsgId fullId() const {
|
|
||||||
return FullMsgId(channelId(), id);
|
return FullMsgId(channelId(), id);
|
||||||
}
|
}
|
||||||
Data::MessagePosition position() const;
|
[[nodiscard]] Data::MessagePosition position() const;
|
||||||
TimeId date() const;
|
[[nodiscard]] TimeId date() const;
|
||||||
|
|
||||||
Data::Media *media() const {
|
[[nodiscard]] static TimeId NewMessageDate(TimeId scheduled);
|
||||||
|
|
||||||
|
[[nodiscard]] Data::Media *media() const {
|
||||||
return _media.get();
|
return _media.get();
|
||||||
}
|
}
|
||||||
virtual void setText(const TextWithEntities &textWithEntities) {
|
virtual void setText(const TextWithEntities &textWithEntities) {
|
||||||
}
|
}
|
||||||
virtual bool textHasLinks() const {
|
[[nodiscard]] virtual bool textHasLinks() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual HistoryMessage *toHistoryMessage() { // dynamic_cast optimize
|
[[nodiscard]] virtual HistoryMessage *toHistoryMessage() { // dynamic_cast optimize
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
virtual const HistoryMessage *toHistoryMessage() const { // dynamic_cast optimize
|
[[nodiscard]] virtual const HistoryMessage *toHistoryMessage() const { // dynamic_cast optimize
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
MsgId replyToId() const;
|
[[nodiscard]] MsgId replyToId() const;
|
||||||
|
|
||||||
not_null<PeerData*> author() const;
|
[[nodiscard]] not_null<PeerData*> author() const;
|
||||||
|
|
||||||
TimeId dateOriginal() const;
|
[[nodiscard]] TimeId dateOriginal() const;
|
||||||
PeerData *senderOriginal() const;
|
[[nodiscard]] PeerData *senderOriginal() const;
|
||||||
const HiddenSenderInfo *hiddenForwardedInfo() const;
|
[[nodiscard]] const HiddenSenderInfo *hiddenForwardedInfo() const;
|
||||||
not_null<PeerData*> fromOriginal() const;
|
[[nodiscard]] not_null<PeerData*> fromOriginal() const;
|
||||||
QString authorOriginal() const;
|
[[nodiscard]] QString authorOriginal() const;
|
||||||
MsgId idOriginal() const;
|
[[nodiscard]] MsgId idOriginal() const;
|
||||||
|
|
||||||
bool isEmpty() const;
|
[[nodiscard]] bool isEmpty() const;
|
||||||
|
|
||||||
MessageGroupId groupId() const;
|
[[nodiscard]] MessageGroupId groupId() const;
|
||||||
|
|
||||||
const HistoryMessageReplyMarkup *inlineReplyMarkup() const {
|
[[nodiscard]] const HistoryMessageReplyMarkup *inlineReplyMarkup() const {
|
||||||
return const_cast<HistoryItem*>(this)->inlineReplyMarkup();
|
return const_cast<HistoryItem*>(this)->inlineReplyMarkup();
|
||||||
}
|
}
|
||||||
const ReplyKeyboard *inlineReplyKeyboard() const {
|
[[nodiscard]] const ReplyKeyboard *inlineReplyKeyboard() const {
|
||||||
return const_cast<HistoryItem*>(this)->inlineReplyKeyboard();
|
return const_cast<HistoryItem*>(this)->inlineReplyKeyboard();
|
||||||
}
|
}
|
||||||
HistoryMessageReplyMarkup *inlineReplyMarkup();
|
[[nodiscard]] HistoryMessageReplyMarkup *inlineReplyMarkup();
|
||||||
ReplyKeyboard *inlineReplyKeyboard();
|
[[nodiscard]] ReplyKeyboard *inlineReplyKeyboard();
|
||||||
|
|
||||||
[[nodiscard]] ChannelData *discussionPostOriginalSender() const;
|
[[nodiscard]] ChannelData *discussionPostOriginalSender() const;
|
||||||
[[nodiscard]] bool isDiscussionPost() const;
|
[[nodiscard]] bool isDiscussionPost() const;
|
||||||
[[nodiscard]] PeerData *displayFrom() const;
|
[[nodiscard]] PeerData *displayFrom() const;
|
||||||
|
|
||||||
virtual std::unique_ptr<HistoryView::Element> createView(
|
[[nodiscard]] virtual std::unique_ptr<HistoryView::Element> createView(
|
||||||
not_null<HistoryView::ElementDelegate*> delegate) = 0;
|
not_null<HistoryView::ElementDelegate*> delegate) = 0;
|
||||||
|
|
||||||
virtual ~HistoryItem();
|
virtual ~HistoryItem();
|
||||||
|
|
||||||
|
MsgId id;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HistoryItem(
|
HistoryItem(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
|
|
|
@ -799,8 +799,8 @@ not_null<HistoryService*> GenerateJoinedMessage(
|
||||||
MTPDmessage::Flags flags) {
|
MTPDmessage::Flags flags) {
|
||||||
return new HistoryService(
|
return new HistoryService(
|
||||||
history,
|
history,
|
||||||
MTPDmessage_ClientFlags(),
|
MTPDmessage_ClientFlag::f_local_history_entry,
|
||||||
clientMsgId(),
|
history->owner().nextLocalMessageId(),
|
||||||
inviteDate,
|
inviteDate,
|
||||||
GenerateJoinedText(history, inviter),
|
GenerateJoinedText(history, inviter),
|
||||||
flags);
|
flags);
|
||||||
|
|
|
@ -634,12 +634,19 @@ HistoryWidget::HistoryWidget(
|
||||||
) | rpl::filter([=](const Api::SendAction &action) {
|
) | rpl::filter([=](const Api::SendAction &action) {
|
||||||
return (action.history == _history);
|
return (action.history == _history);
|
||||||
}) | rpl::start_with_next([=](const Api::SendAction &action) {
|
}) | rpl::start_with_next([=](const Api::SendAction &action) {
|
||||||
fastShowAtEnd(action.history);
|
if (action.options.scheduled) {
|
||||||
const auto lastKeyboardUsed = lastForceReplyReplied(FullMsgId(
|
crl::on_main(this, [=, history = action.history]{
|
||||||
action.history->channelId(),
|
controller->showSection(
|
||||||
action.replyTo));
|
HistoryView::ScheduledMemento(action.history));
|
||||||
if (cancelReply(lastKeyboardUsed) && !action.clearDraft) {
|
});
|
||||||
onCloudDraftSave();
|
} else {
|
||||||
|
fastShowAtEnd(action.history);
|
||||||
|
const auto lastKeyboardUsed = lastForceReplyReplied(FullMsgId(
|
||||||
|
action.history->channelId(),
|
||||||
|
action.replyTo));
|
||||||
|
if (cancelReply(lastKeyboardUsed) && !action.clearDraft) {
|
||||||
|
onCloudDraftSave();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (action.options.handleSupportSwitch) {
|
if (action.options.handleSupportSwitch) {
|
||||||
handleSupportSwitch(action.history);
|
handleSupportSwitch(action.history);
|
||||||
|
@ -2953,7 +2960,7 @@ void HistoryWidget::sendSilent() {
|
||||||
|
|
||||||
void HistoryWidget::sendScheduled() {
|
void HistoryWidget::sendScheduled() {
|
||||||
auto options = Api::SendOptions();
|
auto options = Api::SendOptions();
|
||||||
options.scheduled = INT_MAX;
|
options.scheduled = base::unixtime::now() + 86400;
|
||||||
send(options);
|
send(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4400,7 +4407,8 @@ void HistoryWidget::sendFileConfirmed(
|
||||||
channelId,
|
channelId,
|
||||||
file->to.replyTo));
|
file->to.replyTo));
|
||||||
|
|
||||||
const auto newId = oldId.value_or(FullMsgId(channelId, clientMsgId()));
|
const auto newId = oldId.value_or(
|
||||||
|
FullMsgId(channelId, session().data().nextLocalMessageId()));
|
||||||
auto groupId = file->album ? file->album->groupId : uint64(0);
|
auto groupId = file->album ? file->album->groupId : uint64(0);
|
||||||
if (file->album) {
|
if (file->album) {
|
||||||
const auto proj = [](const SendingAlbum::Item &item) {
|
const auto proj = [](const SendingAlbum::Item &item) {
|
||||||
|
@ -4423,6 +4431,7 @@ void HistoryWidget::sendFileConfirmed(
|
||||||
const auto peer = history->peer;
|
const auto peer = history->peer;
|
||||||
|
|
||||||
auto action = Api::SendAction(history);
|
auto action = Api::SendAction(history);
|
||||||
|
action.options = file->to.options;
|
||||||
action.clearDraft = false;
|
action.clearDraft = false;
|
||||||
action.replyTo = file->to.replyTo;
|
action.replyTo = file->to.replyTo;
|
||||||
action.generateLocal = true;
|
action.generateLocal = true;
|
||||||
|
@ -4469,6 +4478,12 @@ void HistoryWidget::sendFileConfirmed(
|
||||||
if (groupId) {
|
if (groupId) {
|
||||||
flags |= MTPDmessage::Flag::f_grouped_id;
|
flags |= MTPDmessage::Flag::f_grouped_id;
|
||||||
}
|
}
|
||||||
|
if (file->to.options.scheduled) {
|
||||||
|
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||||
|
} else {
|
||||||
|
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||||
|
}
|
||||||
|
|
||||||
const auto messageFromId = channelPost ? 0 : session().userId();
|
const auto messageFromId = channelPost ? 0 : session().userId();
|
||||||
const auto messagePostAuthor = channelPost
|
const auto messagePostAuthor = channelPost
|
||||||
? App::peerName(session().user())
|
? App::peerName(session().user())
|
||||||
|
@ -4489,7 +4504,7 @@ void HistoryWidget::sendFileConfirmed(
|
||||||
MTPMessageFwdHeader(),
|
MTPMessageFwdHeader(),
|
||||||
MTPint(),
|
MTPint(),
|
||||||
MTP_int(file->to.replyTo),
|
MTP_int(file->to.replyTo),
|
||||||
MTP_int(base::unixtime::now()),
|
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||||
MTP_string(caption.text),
|
MTP_string(caption.text),
|
||||||
photo,
|
photo,
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
|
@ -4525,7 +4540,7 @@ void HistoryWidget::sendFileConfirmed(
|
||||||
MTPMessageFwdHeader(),
|
MTPMessageFwdHeader(),
|
||||||
MTPint(),
|
MTPint(),
|
||||||
MTP_int(file->to.replyTo),
|
MTP_int(file->to.replyTo),
|
||||||
MTP_int(base::unixtime::now()),
|
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||||
MTP_string(caption.text),
|
MTP_string(caption.text),
|
||||||
document,
|
document,
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
|
@ -4564,7 +4579,8 @@ void HistoryWidget::sendFileConfirmed(
|
||||||
MTPMessageFwdHeader(),
|
MTPMessageFwdHeader(),
|
||||||
MTPint(),
|
MTPint(),
|
||||||
MTP_int(file->to.replyTo),
|
MTP_int(file->to.replyTo),
|
||||||
MTP_int(base::unixtime::now()),
|
MTP_int(
|
||||||
|
HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||||
MTP_string(caption.text),
|
MTP_string(caption.text),
|
||||||
document,
|
document,
|
||||||
MTPReplyMarkup(),
|
MTPReplyMarkup(),
|
||||||
|
|
|
@ -3899,19 +3899,25 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||||
const auto &d = update.c_updateMessageID();
|
const auto &d = update.c_updateMessageID();
|
||||||
const auto randomId = d.vrandom_id().v;
|
const auto randomId = d.vrandom_id().v;
|
||||||
if (const auto id = session().data().messageIdByRandomId(randomId)) {
|
if (const auto id = session().data().messageIdByRandomId(randomId)) {
|
||||||
const auto channel = id.channel;
|
|
||||||
const auto newId = d.vid().v;
|
const auto newId = d.vid().v;
|
||||||
if (const auto local = session().data().message(id)) {
|
if (const auto local = session().data().message(id)) {
|
||||||
const auto existing = session().data().message(channel, newId);
|
if (local->isScheduled()) {
|
||||||
if (existing && !local->mainView()) {
|
session().data().scheduledMessages().apply(d, local);
|
||||||
const auto history = local->history();
|
|
||||||
local->destroy();
|
|
||||||
history->requestChatListMessage();
|
|
||||||
} else {
|
} else {
|
||||||
if (existing) {
|
const auto channel = id.channel;
|
||||||
existing->destroy();
|
const auto existing = session().data().message(
|
||||||
|
channel,
|
||||||
|
newId);
|
||||||
|
if (existing && !local->mainView()) {
|
||||||
|
const auto history = local->history();
|
||||||
|
local->destroy();
|
||||||
|
history->requestChatListMessage();
|
||||||
|
} else {
|
||||||
|
if (existing) {
|
||||||
|
existing->destroy();
|
||||||
|
}
|
||||||
|
local->setRealId(d.vid().v);
|
||||||
}
|
}
|
||||||
local->setRealId(d.vid().v);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session().data().unregisterMessageRandomId(randomId);
|
session().data().unregisterMessageRandomId(randomId);
|
||||||
|
|
|
@ -66,8 +66,8 @@ enum class MTPDmessage_ClientFlag : uint32 {
|
||||||
// message has no media and only a several emoji text
|
// message has no media and only a several emoji text
|
||||||
f_isolated_emoji = (1U << 21),
|
f_isolated_emoji = (1U << 21),
|
||||||
|
|
||||||
// update this when adding new client side flags
|
// message is local message existing in the message history
|
||||||
MIN_FIELD = (1U << 21),
|
f_local_history_entry = (1U << 20),
|
||||||
};
|
};
|
||||||
inline constexpr bool is_flag_type(MTPDmessage_ClientFlag) { return true; }
|
inline constexpr bool is_flag_type(MTPDmessage_ClientFlag) { return true; }
|
||||||
using MTPDmessage_ClientFlags = base::flags<MTPDmessage_ClientFlag>;
|
using MTPDmessage_ClientFlags = base::flags<MTPDmessage_ClientFlag>;
|
||||||
|
|
|
@ -1520,7 +1520,9 @@ void FormController::uploadEncryptedFile(
|
||||||
prepared->setFileData(prepared->content);
|
prepared->setFileData(prepared->content);
|
||||||
prepared->filemd5 = file.uploadData->md5checksum;
|
prepared->filemd5 = file.uploadData->md5checksum;
|
||||||
|
|
||||||
file.uploadData->fullId = FullMsgId(0, clientMsgId());
|
file.uploadData->fullId = FullMsgId(
|
||||||
|
0,
|
||||||
|
Auth().data().nextLocalMessageId());
|
||||||
Auth().uploader().upload(file.uploadData->fullId, std::move(prepared));
|
Auth().uploader().upload(file.uploadData->fullId, std::move(prepared));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -429,7 +429,7 @@ void ChatBackground::checkUploadWallPaper() {
|
||||||
|
|
||||||
const auto ready = PrepareWallPaper(_original);
|
const auto ready = PrepareWallPaper(_original);
|
||||||
const auto documentId = ready.id;
|
const auto documentId = ready.id;
|
||||||
_wallPaperUploadId = FullMsgId(0, clientMsgId());
|
_wallPaperUploadId = FullMsgId(0, _session->data().nextLocalMessageId());
|
||||||
_session->uploader().uploadMedia(_wallPaperUploadId, ready);
|
_session->uploader().uploadMedia(_wallPaperUploadId, ready);
|
||||||
if (_wallPaperUploadLifetime) {
|
if (_wallPaperUploadLifetime) {
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue