Bundle silent and scheduled to Api::SendOptions.

This commit is contained in:
John Preston 2019-08-12 13:11:34 +01:00
parent 0b08810d5a
commit caef7dde24
27 changed files with 413 additions and 349 deletions

View File

@ -1240,6 +1240,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_send_button" = "Send"; "lng_send_button" = "Send";
"lng_send_silent_message" = "Send without sound"; "lng_send_silent_message" = "Send without sound";
"lng_schedule_message" = "Schedule message";
"lng_message_ph" = "Write a message..."; "lng_message_ph" = "Write a message...";
"lng_broadcast_ph" = "Broadcast a message..."; "lng_broadcast_ph" = "Broadcast a message...";
"lng_broadcast_silent_ph" = "Silent broadcast..."; "lng_broadcast_silent_ph" = "Silent broadcast...";

View File

@ -0,0 +1,39 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Api {
struct SendOptions {
TimeId scheduled = 0;
bool silent = false;
bool handleSupportSwitch = false;
bool removeWebPageId = false;
};
struct SendAction {
explicit SendAction(not_null<History*> history) : history(history) {
}
not_null<History*> history;
SendOptions options;
MsgId replyTo = 0;
bool clearDraft = false;
bool generateLocal = true;
};
struct MessageToSend {
explicit MessageToSend(not_null<History*> history) : action(history) {
}
SendAction action;
TextWithTags textWithTags;
WebPageId webPageId = 0;
};
} // namespace Api

View File

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_message.h" // NewMessageFlags. #include "history/history_message.h" // NewMessageFlags.
#include "chat_helpers/message_field.h" // ConvertTextTagsToEntities.
#include "ui/text/text_entity.h" // TextWithEntities. #include "ui/text/text_entity.h" // TextWithEntities.
#include "main/main_session.h" #include "main/main_session.h"
#include "mainwidget.h" #include "mainwidget.h"
@ -26,24 +27,18 @@ namespace {
template <typename MediaData> template <typename MediaData>
void SendExistingMedia( void SendExistingMedia(
not_null<History*> history, Api::MessageToSend &&message,
not_null<MediaData*> media, not_null<MediaData*> media,
const MTPInputMedia &inputMedia, const MTPInputMedia &inputMedia,
Data::FileOrigin origin, Data::FileOrigin origin) {
TextWithEntities caption, const auto history = message.action.history;
MsgId replyToId,
bool silent) {
const auto peer = history->peer; const auto peer = history->peer;
const auto session = &history->session(); const auto session = &history->session();
const auto api = &session->api(); const auto api = &session->api();
auto options = ApiWrap::SendOptions(history); message.action.clearDraft = false;
options.clearDraft = false; message.action.generateLocal = true;
options.replyTo = replyToId; api->sendAction(message.action);
options.generateLocal = true;
options.silent = silent;
api->sendAction(options);
const auto newId = FullMsgId(peerToChannel(peer->id), clientMsgId()); const auto newId = FullMsgId(peerToChannel(peer->id), clientMsgId());
const auto randomId = rand_value<uint64>(); const auto randomId = rand_value<uint64>();
@ -51,12 +46,12 @@ void SendExistingMedia(
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media; auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
auto clientFlags = NewMessageClientFlags(); auto clientFlags = NewMessageClientFlags();
auto sendFlags = MTPmessages_SendMedia::Flags(0); auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (options.replyTo) { if (message.action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id; flags |= MTPDmessage::Flag::f_reply_to_msg_id;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id; sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
} }
const auto channelPost = peer->isChannel() && !peer->isMegagroup(); const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = options.silent const auto silentPost = message.action.options.silent
|| (channelPost && session->data().notifySilentPosts(peer)); || (channelPost && session->data().notifySilentPosts(peer));
if (channelPost) { if (channelPost) {
flags |= MTPDmessage::Flag::f_views; flags |= MTPDmessage::Flag::f_views;
@ -75,6 +70,10 @@ void SendExistingMedia(
? App::peerName(session->user()) ? App::peerName(session->user())
: QString(); : QString();
auto caption = TextWithEntities{
message.textWithTags.text,
ConvertTextTagsToEntities(message.textWithTags.tags)
};
TextUtilities::Trim(caption); TextUtilities::Trim(caption);
auto sentEntities = TextUtilities::EntitiesToMTP( auto sentEntities = TextUtilities::EntitiesToMTP(
caption.entities, caption.entities,
@ -82,7 +81,7 @@ void SendExistingMedia(
if (!sentEntities.v.isEmpty()) { if (!sentEntities.v.isEmpty()) {
sendFlags |= MTPmessages_SendMedia::Flag::f_entities; sendFlags |= MTPmessages_SendMedia::Flag::f_entities;
} }
const auto replyTo = options.replyTo; const auto replyTo = message.action.replyTo;
const auto captionText = caption.text; const auto captionText = caption.text;
session->data().registerMessageRandomId(randomId, newId); session->data().registerMessageRandomId(randomId, newId);
@ -137,36 +136,23 @@ void SendExistingMedia(
performRequest(); performRequest();
if (const auto main = App::main()) { if (const auto main = App::main()) {
main->finishForwarding(history, options.silent); main->finishForwarding(message.action);
} }
} }
} // namespace } // namespace
void SendExistingDocument( void SendExistingDocument(
not_null<History*> history, Api::MessageToSend &&message,
not_null<DocumentData*> document, not_null<DocumentData*> document) {
bool silent) {
SendExistingDocument(history, document, {}, 0, silent);
}
void SendExistingDocument(
not_null<History*> history,
not_null<DocumentData*> document,
TextWithEntities caption,
MsgId replyToId,
bool silent) {
SendExistingMedia( SendExistingMedia(
history, std::move(message),
document, document,
MTP_inputMediaDocument( MTP_inputMediaDocument(
MTP_flags(0), MTP_flags(0),
document->mtpInput(), document->mtpInput(),
MTPint()), MTPint()),
document->stickerOrGifOrigin(), document->stickerOrGifOrigin());
caption,
replyToId,
silent);
if (document->sticker()) { if (document->sticker()) {
if (const auto main = App::main()) { if (const auto main = App::main()) {
@ -177,29 +163,16 @@ void SendExistingDocument(
} }
void SendExistingPhoto( void SendExistingPhoto(
not_null<History*> history, Api::MessageToSend &&message,
not_null<PhotoData*> photo, not_null<PhotoData*> photo) {
bool silent) {
SendExistingPhoto(history, photo, {}, 0, silent);
}
void SendExistingPhoto(
not_null<History*> history,
not_null<PhotoData*> photo,
TextWithEntities caption,
MsgId replyToId,
bool silent) {
SendExistingMedia( SendExistingMedia(
history, std::move(message),
photo, photo,
MTP_inputMediaPhoto( MTP_inputMediaPhoto(
MTP_flags(0), MTP_flags(0),
photo->mtpInput(), photo->mtpInput(),
MTPint()), MTPint()),
Data::FileOrigin(), Data::FileOrigin());
caption,
replyToId,
silent);
} }
} // namespace Api } // namespace Api

View File

@ -9,32 +9,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class History; class History;
class DocumentData; class DocumentData;
struct TextWithEntities;
namespace Api { namespace Api {
void SendExistingDocument( struct MessageToSend;
not_null<History*> history,
not_null<DocumentData*> document,
bool silent = false);
void SendExistingDocument( void SendExistingDocument(
not_null<History*> history, Api::MessageToSend &&message,
not_null<DocumentData*> document, not_null<DocumentData*> document);
TextWithEntities caption,
MsgId replyToId = 0,
bool silent = false);
void SendExistingPhoto( void SendExistingPhoto(
not_null<History*> history, Api::MessageToSend &&message,
not_null<PhotoData*> photo, not_null<PhotoData*> photo);
bool silent = false);
void SendExistingPhoto(
not_null<History*> history,
not_null<PhotoData*> photo,
TextWithEntities caption,
MsgId replyToId = 0,
bool silent = false);
} // namespace Api } // namespace Api

View File

@ -156,14 +156,6 @@ MTPVector<MTPDocumentAttribute> ComposeSendingDocumentAttributes(
} // namespace } // namespace
ApiWrap::SendOptions::SendOptions(not_null<History*> history)
: history(history) {
}
ApiWrap::MessageToSend::MessageToSend(not_null<History*> history)
: history(history) {
}
MTPInputPrivacyKey ApiWrap::Privacy::Input(Key key) { MTPInputPrivacyKey ApiWrap::Privacy::Input(Key key) {
switch (key) { switch (key) {
case Privacy::Key::Calls: return MTP_inputPrivacyKeyPhoneCall(); case Privacy::Key::Calls: return MTP_inputPrivacyKeyPhoneCall();
@ -4386,15 +4378,15 @@ void ApiWrap::userPhotosDone(
// )).send(); // )).send();
//} //}
void ApiWrap::sendAction(const SendOptions &options) { void ApiWrap::sendAction(const SendAction &action) {
readServerHistory(options.history); readServerHistory(action.history);
options.history->getReadyFor(ShowAtTheEndMsgId); action.history->getReadyFor(ShowAtTheEndMsgId);
_sendActions.fire_copy(options); _sendActions.fire_copy(action);
} }
void ApiWrap::forwardMessages( void ApiWrap::forwardMessages(
HistoryItemsList &&items, HistoryItemsList &&items,
const SendOptions &options, const SendAction &action,
FnMut<void()> &&successCallback) { FnMut<void()> &&successCallback) {
Expects(!items.empty()); Expects(!items.empty());
@ -4410,14 +4402,14 @@ void ApiWrap::forwardMessages(
} }
const auto count = int(items.size()); const auto count = int(items.size());
const auto genClientSideMessage = options.generateLocal && (count < 2); const auto genClientSideMessage = action.generateLocal && (count < 2);
const auto history = options.history; const auto history = action.history;
const auto peer = history->peer; const auto peer = history->peer;
readServerHistory(history); readServerHistory(history);
const auto channelPost = peer->isChannel() && !peer->isMegagroup(); const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = options.silent const auto silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer)); || (channelPost && _session->data().notifySilentPosts(peer));
auto flags = MTPDmessage::Flags(0); auto flags = MTPDmessage::Flags(0);
@ -4530,14 +4522,14 @@ void ApiWrap::shareContact(
const QString &phone, const QString &phone,
const QString &firstName, const QString &firstName,
const QString &lastName, const QString &lastName,
const SendOptions &options) { const SendAction &action) {
const auto userId = UserId(0); const auto userId = UserId(0);
sendSharedContact(phone, firstName, lastName, userId, options); sendSharedContact(phone, firstName, lastName, userId, action);
} }
void ApiWrap::shareContact( void ApiWrap::shareContact(
not_null<UserData*> user, not_null<UserData*> user,
const SendOptions &options) { const SendAction &action) {
const auto userId = peerToUser(user->id); const auto userId = peerToUser(user->id);
const auto phone = _session->data().findContactPhone(user); const auto phone = _session->data().findContactPhone(user);
if (phone.isEmpty()) { if (phone.isEmpty()) {
@ -4548,7 +4540,7 @@ void ApiWrap::shareContact(
user->firstName, user->firstName,
user->lastName, user->lastName,
userId, userId,
options); action);
} }
void ApiWrap::sendSharedContact( void ApiWrap::sendSharedContact(
@ -4556,10 +4548,10 @@ void ApiWrap::sendSharedContact(
const QString &firstName, const QString &firstName,
const QString &lastName, const QString &lastName,
UserId userId, UserId userId,
const SendOptions &options) { const SendAction &action) {
sendAction(options); sendAction(action);
const auto history = options.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(), clientMsgId());
@ -4567,7 +4559,7 @@ void ApiWrap::sendSharedContact(
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media; auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
auto clientFlags = NewMessageClientFlags(); auto clientFlags = NewMessageClientFlags();
if (options.replyTo) { if (action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id; flags |= MTPDmessage::Flag::f_reply_to_msg_id;
} }
if (channelPost) { if (channelPost) {
@ -4593,7 +4585,7 @@ void ApiWrap::sendSharedContact(
peerToMTP(peer->id), peerToMTP(peer->id),
MTPMessageFwdHeader(), MTPMessageFwdHeader(),
MTPint(), MTPint(),
MTP_int(options.replyTo), MTP_int(action.replyTo),
MTP_int(base::unixtime::now()), MTP_int(base::unixtime::now()),
MTP_string(), MTP_string(),
MTP_messageMediaContact( MTP_messageMediaContact(
@ -4618,7 +4610,9 @@ void ApiWrap::sendSharedContact(
MTP_string(firstName), MTP_string(firstName),
MTP_string(lastName), MTP_string(lastName),
MTP_string(vcard)); MTP_string(vcard));
sendMedia(item, media, _session->data().notifySilentPosts(peer)); auto options = action.options;
options.silent = _session->data().notifySilentPosts(peer);
sendMedia(item, media, options);
if (const auto main = App::main()) { if (const auto main = App::main()) {
_session->data().sendHistoryChangeNotifications(); _session->data().sendHistoryChangeNotifications();
@ -4631,9 +4625,9 @@ void ApiWrap::sendVoiceMessage(
QByteArray result, QByteArray result,
VoiceWaveform waveform, VoiceWaveform waveform,
int duration, int duration,
const SendOptions &options) { const SendAction &action) {
const auto caption = TextWithTags(); const auto caption = TextWithTags();
const auto to = fileLoadTaskOptions(options); const auto to = fileLoadTaskOptions(action);
_fileLoader->addTask(std::make_unique<FileLoadTask>( _fileLoader->addTask(std::make_unique<FileLoadTask>(
result, result,
duration, duration,
@ -4646,12 +4640,12 @@ void ApiWrap::editMedia(
Storage::PreparedList &&list, Storage::PreparedList &&list,
SendMediaType type, SendMediaType type,
TextWithTags &&caption, TextWithTags &&caption,
const SendOptions &options, const SendAction &action,
MsgId msgIdToEdit) { MsgId msgIdToEdit) {
if (list.files.empty()) return; if (list.files.empty()) return;
auto &file = list.files.front(); auto &file = list.files.front();
const auto to = fileLoadTaskOptions(options); const auto to = fileLoadTaskOptions(action);
_fileLoader->addTask(std::make_unique<FileLoadTask>( _fileLoader->addTask(std::make_unique<FileLoadTask>(
file.path, file.path,
file.content, file.content,
@ -4668,22 +4662,22 @@ void ApiWrap::sendFiles(
SendMediaType type, SendMediaType type,
TextWithTags &&caption, TextWithTags &&caption,
std::shared_ptr<SendingAlbum> album, std::shared_ptr<SendingAlbum> album,
const SendOptions &options) { const SendAction &action) {
const auto haveCaption = !caption.text.isEmpty(); const auto haveCaption = !caption.text.isEmpty();
const auto isAlbum = (album != nullptr); const auto isAlbum = (album != nullptr);
const auto compressImages = (type == SendMediaType::Photo); const auto compressImages = (type == SendMediaType::Photo);
if (haveCaption && !list.canAddCaption(isAlbum, compressImages)) { if (haveCaption && !list.canAddCaption(isAlbum, compressImages)) {
auto message = MessageToSend(options.history); auto message = MessageToSend(action.history);
message.textWithTags = std::move(caption); message.textWithTags = std::move(caption);
message.replyTo = options.replyTo; message.action = action;
message.clearDraft = false; message.action.clearDraft = false;
sendMessage(std::move(message)); sendMessage(std::move(message));
caption = TextWithTags(); caption = TextWithTags();
} }
const auto to = fileLoadTaskOptions(options); const auto to = fileLoadTaskOptions(action);
if (album) { if (album) {
album->silent = to.silent; album->options = to.options;
} }
auto tasks = std::vector<std::unique_ptr<Task>>(); auto tasks = std::vector<std::unique_ptr<Task>>();
tasks.reserve(list.files.size()); tasks.reserve(list.files.size());
@ -4722,8 +4716,8 @@ void ApiWrap::sendFiles(
void ApiWrap::sendFile( void ApiWrap::sendFile(
const QByteArray &fileContent, const QByteArray &fileContent,
SendMediaType type, SendMediaType type,
const SendOptions &options) { const SendAction &action) {
const auto to = fileLoadTaskOptions(options); const auto to = fileLoadTaskOptions(action);
auto caption = TextWithTags(); auto caption = TextWithTags();
_fileLoader->addTask(std::make_unique<FileLoadTask>( _fileLoader->addTask(std::make_unique<FileLoadTask>(
QString(), QString(),
@ -4737,7 +4731,7 @@ void ApiWrap::sendFile(
void ApiWrap::sendUploadedPhoto( void ApiWrap::sendUploadedPhoto(
FullMsgId localId, FullMsgId localId,
const MTPInputFile &file, const MTPInputFile &file,
bool silent) { Api::SendOptions options) {
if (const auto item = _session->data().message(localId)) { if (const auto item = _session->data().message(localId)) {
const auto media = MTP_inputMediaUploadedPhoto( const auto media = MTP_inputMediaUploadedPhoto(
MTP_flags(0), MTP_flags(0),
@ -4747,7 +4741,7 @@ void ApiWrap::sendUploadedPhoto(
if (const auto groupId = item->groupId()) { if (const auto groupId = item->groupId()) {
uploadAlbumMedia(item, groupId, media); uploadAlbumMedia(item, groupId, media);
} else { } else {
sendMedia(item, media, silent); sendMedia(item, media, options);
} }
} }
} }
@ -4756,7 +4750,7 @@ void ApiWrap::sendUploadedDocument(
FullMsgId localId, FullMsgId localId,
const MTPInputFile &file, const MTPInputFile &file,
const std::optional<MTPInputFile> &thumb, const std::optional<MTPInputFile> &thumb,
bool silent) { Api::SendOptions options) {
if (const auto item = _session->data().message(localId)) { if (const auto item = _session->data().message(localId)) {
auto media = item->media(); auto media = item->media();
if (auto document = media ? media->document() : nullptr) { if (auto document = media ? media->document() : nullptr) {
@ -4779,7 +4773,7 @@ void ApiWrap::sendUploadedDocument(
if (groupId) { if (groupId) {
uploadAlbumMedia(item, groupId, media); uploadAlbumMedia(item, groupId, media);
} else { } else {
sendMedia(item, media, silent); sendMedia(item, media, options);
} }
} }
} }
@ -4789,7 +4783,7 @@ void ApiWrap::editUploadedFile(
FullMsgId localId, FullMsgId localId,
const MTPInputFile &file, const MTPInputFile &file,
const std::optional<MTPInputFile> &thumb, const std::optional<MTPInputFile> &thumb,
bool silent, Api::SendOptions options,
bool isDocument) { bool isDocument) {
const auto item = _session->data().message(localId); const auto item = _session->data().message(localId);
if (!item) { if (!item) {
@ -4887,18 +4881,13 @@ void ApiWrap::cancelLocalItem(not_null<HistoryItem*> item) {
} }
void ApiWrap::sendMessage(MessageToSend &&message) { void ApiWrap::sendMessage(MessageToSend &&message) {
const auto history = message.history; const auto history = message.action.history;
const auto peer = history->peer; const auto peer = history->peer;
auto &textWithTags = message.textWithTags; auto &textWithTags = message.textWithTags;
auto options = ApiWrap::SendOptions(history); auto action = message.action;
options.clearDraft = message.clearDraft; action.generateLocal = true;
options.replyTo = message.replyTo; sendAction(action);
options.silent = message.silent;
options.generateLocal = true;
options.webPageId = message.webPageId;
options.handleSupportSwitch = message.handleSupportSwitch;
sendAction(options);
if (!peer->canWrite()) { if (!peer->canWrite()) {
return; return;
@ -4930,7 +4919,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_entities; auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_entities;
auto clientFlags = NewMessageClientFlags(); auto clientFlags = NewMessageClientFlags();
auto sendFlags = MTPmessages_SendMessage::Flags(0); auto sendFlags = MTPmessages_SendMessage::Flags(0);
if (message.replyTo) { if (action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id; flags |= MTPDmessage::Flag::f_reply_to_msg_id;
sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to_msg_id; sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to_msg_id;
} }
@ -4946,7 +4935,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
flags |= MTPDmessage::Flag::f_media; flags |= MTPDmessage::Flag::f_media;
} }
const auto channelPost = peer->isChannel() && !peer->isMegagroup(); const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = message.silent const auto silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer)); || (channelPost && _session->data().notifySilentPosts(peer));
if (channelPost) { if (channelPost) {
flags |= MTPDmessage::Flag::f_views; flags |= MTPDmessage::Flag::f_views;
@ -4965,7 +4954,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
if (!sentEntities.v.isEmpty()) { if (!sentEntities.v.isEmpty()) {
sendFlags |= MTPmessages_SendMessage::Flag::f_entities; sendFlags |= MTPmessages_SendMessage::Flag::f_entities;
} }
if (message.clearDraft) { if (action.clearDraft) {
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft; sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
history->clearCloudDraft(); history->clearCloudDraft();
history->setSentDraftText(QString()); history->setSentDraftText(QString());
@ -4982,7 +4971,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
peerToMTP(peer->id), peerToMTP(peer->id),
MTPMessageFwdHeader(), MTPMessageFwdHeader(),
MTPint(), MTPint(),
MTP_int(message.replyTo), MTP_int(action.replyTo),
MTP_int(base::unixtime::now()), MTP_int(base::unixtime::now()),
msgText, msgText,
media, media,
@ -4999,7 +4988,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
history->sendRequestId = request(MTPmessages_SendMessage( history->sendRequestId = request(MTPmessages_SendMessage(
MTP_flags(sendFlags), MTP_flags(sendFlags),
peer->input, peer->input,
MTP_int(message.replyTo), MTP_int(action.replyTo),
msgText, msgText,
MTP_long(randomId), MTP_long(randomId),
MTPReplyMarkup(), MTPReplyMarkup(),
@ -5020,7 +5009,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
} }
if (const auto main = App::main()) { if (const auto main = App::main()) {
main->finishForwarding(history, message.silent); main->finishForwarding(action);
} }
} }
@ -5059,10 +5048,10 @@ void ApiWrap::sendBotStart(not_null<UserData*> bot, PeerData *chat) {
void ApiWrap::sendInlineResult( void ApiWrap::sendInlineResult(
not_null<UserData*> bot, not_null<UserData*> bot,
not_null<InlineBots::Result*> data, not_null<InlineBots::Result*> data,
const SendOptions &options) { const SendAction &action) {
sendAction(options); sendAction(action);
const auto history = options.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), clientMsgId());
const auto randomId = rand_value<uint64>(); const auto randomId = rand_value<uint64>();
@ -5070,12 +5059,12 @@ void ApiWrap::sendInlineResult(
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media; auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
auto clientFlags = NewMessageClientFlags(); auto clientFlags = NewMessageClientFlags();
auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0; auto sendFlags = MTPmessages_SendInlineBotResult::Flag::f_clear_draft | 0;
if (options.replyTo) { if (action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id; flags |= MTPDmessage::Flag::f_reply_to_msg_id;
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id; sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
} }
bool channelPost = peer->isChannel() && !peer->isMegagroup(); bool channelPost = peer->isChannel() && !peer->isMegagroup();
bool silentPost = options.silent bool silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer)); || (channelPost && _session->data().notifySilentPosts(peer));
if (channelPost) { if (channelPost) {
flags |= MTPDmessage::Flag::f_views; flags |= MTPDmessage::Flag::f_views;
@ -5111,7 +5100,7 @@ void ApiWrap::sendInlineResult(
messageFromId, messageFromId,
messageDate, messageDate,
messageViaBotId, messageViaBotId,
options.replyTo, action.replyTo,
messagePostAuthor); messagePostAuthor);
history->clearCloudDraft(); history->clearCloudDraft();
@ -5120,7 +5109,7 @@ void ApiWrap::sendInlineResult(
history->sendRequestId = request(MTPmessages_SendInlineBotResult( history->sendRequestId = request(MTPmessages_SendInlineBotResult(
MTP_flags(sendFlags), MTP_flags(sendFlags),
peer->input, peer->input,
MTP_int(options.replyTo), MTP_int(action.replyTo),
MTP_long(randomId), MTP_long(randomId),
MTP_long(data->getQueryId()), MTP_long(data->getQueryId()),
MTP_string(data->getId()), MTP_string(data->getId()),
@ -5135,7 +5124,7 @@ void ApiWrap::sendInlineResult(
).send(); ).send();
if (const auto main = App::main()) { if (const auto main = App::main()) {
main->finishForwarding(history, options.silent); main->finishForwarding(action);
} }
} }
@ -5217,17 +5206,17 @@ void ApiWrap::uploadAlbumMedia(
void ApiWrap::sendMedia( void ApiWrap::sendMedia(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPInputMedia &media, const MTPInputMedia &media,
bool silent) { Api::SendOptions options) {
const auto randomId = rand_value<uint64>(); const auto randomId = rand_value<uint64>();
_session->data().registerMessageRandomId(randomId, item->fullId()); _session->data().registerMessageRandomId(randomId, item->fullId());
sendMediaWithRandomId(item, media, silent, randomId); sendMediaWithRandomId(item, media, options, randomId);
} }
void ApiWrap::sendMediaWithRandomId( void ApiWrap::sendMediaWithRandomId(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPInputMedia &media, const MTPInputMedia &media,
bool silent, Api::SendOptions options,
uint64 randomId) { uint64 randomId) {
const auto history = item->history(); const auto history = item->history();
const auto replyTo = item->replyToId(); const auto replyTo = item->replyToId();
@ -5242,7 +5231,7 @@ void ApiWrap::sendMediaWithRandomId(
| (replyTo | (replyTo
? MTPmessages_SendMedia::Flag::f_reply_to_msg_id ? MTPmessages_SendMedia::Flag::f_reply_to_msg_id
: MTPmessages_SendMedia::Flag(0)) : MTPmessages_SendMedia::Flag(0))
| (silent | (options.silent
? MTPmessages_SendMedia::Flag::f_silent ? MTPmessages_SendMedia::Flag::f_silent
: MTPmessages_SendMedia::Flag(0)) : MTPmessages_SendMedia::Flag(0))
| (!sentEntities.v.isEmpty() | (!sentEntities.v.isEmpty()
@ -5328,7 +5317,7 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
sendMediaWithRandomId( sendMediaWithRandomId(
sample, sample,
single.vmedia(), single.vmedia(),
album->silent, album->options,
single.vrandom_id().v); single.vrandom_id().v);
_sendingAlbums.remove(groupId); _sendingAlbums.remove(groupId);
return; return;
@ -5339,7 +5328,7 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
| (replyTo | (replyTo
? MTPmessages_SendMultiMedia::Flag::f_reply_to_msg_id ? MTPmessages_SendMultiMedia::Flag::f_reply_to_msg_id
: MTPmessages_SendMultiMedia::Flag(0)) : MTPmessages_SendMultiMedia::Flag(0))
| (album->silent | (album->options.silent
? MTPmessages_SendMultiMedia::Flag::f_silent ? MTPmessages_SendMultiMedia::Flag::f_silent
: MTPmessages_SendMultiMedia::Flag(0)); : MTPmessages_SendMultiMedia::Flag(0));
const auto peer = history->peer; const auto peer = history->peer;
@ -5365,12 +5354,16 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
).send(); ).send();
} }
FileLoadTo ApiWrap::fileLoadTaskOptions(const SendOptions &options) const { FileLoadTo ApiWrap::fileLoadTaskOptions(const SendAction &action) const {
const auto peer = options.history->peer; const auto peer = action.history->peer;
auto options = action.options;
if (_session->data().notifySilentPosts(peer)) {
options.silent = true;
}
return FileLoadTo( return FileLoadTo(
peer->id, peer->id,
options.silent || _session->data().notifySilentPosts(peer), action.options,
options.replyTo); action.replyTo);
} }
void ApiWrap::requestSupportContact(FnMut<void(const MTPUser &)> callback) { void ApiWrap::requestSupportContact(FnMut<void(const MTPUser &)> callback) {
@ -5802,30 +5795,30 @@ void ApiWrap::setSelfDestructDays(int days) {
void ApiWrap::createPoll( void ApiWrap::createPoll(
const PollData &data, const PollData &data,
const SendOptions &options, const SendAction &action,
FnMut<void()> done, FnMut<void()> done,
FnMut<void(const RPCError &error)> fail) { FnMut<void(const RPCError &error)> fail) {
sendAction(options); sendAction(action);
const auto history = options.history; const auto history = action.history;
const auto peer = history->peer; const auto peer = history->peer;
auto sendFlags = MTPmessages_SendMedia::Flags(0); auto sendFlags = MTPmessages_SendMedia::Flags(0);
if (options.replyTo) { if (action.replyTo) {
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id; sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
} }
if (options.clearDraft) { if (action.clearDraft) {
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft; sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
history->clearLocalDraft(); history->clearLocalDraft();
history->clearCloudDraft(); history->clearCloudDraft();
} }
const auto channelPost = peer->isChannel() && !peer->isMegagroup(); const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = options.silent const auto silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer)); || (channelPost && _session->data().notifySilentPosts(peer));
if (silentPost) { if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent; sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
} }
const auto replyTo = options.replyTo; const auto replyTo = action.replyTo;
history->sendRequestId = request(MTPmessages_SendMedia( history->sendRequestId = request(MTPmessages_SendMedia(
MTP_flags(sendFlags), MTP_flags(sendFlags),
peer->input, peer->input,

View File

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include <rpl/event_stream.h> #include "api/api_common.h"
#include "base/timer.h" #include "base/timer.h"
#include "base/flat_map.h" #include "base/flat_map.h"
#include "base/flat_set.h" #include "base/flat_set.h"
@ -87,6 +87,9 @@ QString RequestKey(Types &&...values) {
class ApiWrap : public MTP::Sender, private base::Subscriber { class ApiWrap : public MTP::Sender, private base::Subscriber {
public: public:
using SendAction = Api::SendAction;
using MessageToSend = Api::MessageToSend;
struct Privacy { struct Privacy {
enum class Key { enum class Key {
PhoneNumber, PhoneNumber,
@ -366,31 +369,21 @@ public:
not_null<PeerData*> peer, not_null<PeerData*> peer,
const std::vector<not_null<UserData*>> &users); const std::vector<not_null<UserData*>> &users);
struct SendOptions {
SendOptions(not_null<History*> history);
not_null<History*> history; rpl::producer<SendAction> sendActions() const {
MsgId replyTo = 0;
WebPageId webPageId = 0;
bool silent = false;
bool clearDraft = false;
bool generateLocal = true;
bool handleSupportSwitch = false;
};
rpl::producer<SendOptions> sendActions() const {
return _sendActions.events(); return _sendActions.events();
} }
void sendAction(const SendOptions &options); void sendAction(const SendAction &action);
void forwardMessages( void forwardMessages(
HistoryItemsList &&items, HistoryItemsList &&items,
const SendOptions &options, const SendAction &action,
FnMut<void()> &&successCallback = nullptr); FnMut<void()> &&successCallback = nullptr);
void shareContact( void shareContact(
const QString &phone, const QString &phone,
const QString &firstName, const QString &firstName,
const QString &lastName, const QString &lastName,
const SendOptions &options); const SendAction &action);
void shareContact(not_null<UserData*> user, const SendOptions &options); void shareContact(not_null<UserData*> user, const SendAction &action);
void readServerHistory(not_null<History*> history); void readServerHistory(not_null<History*> history);
void readServerHistoryForce(not_null<History*> history); void readServerHistoryForce(not_null<History*> history);
//void readFeed( // #feed //void readFeed( // #feed
@ -401,60 +394,49 @@ public:
QByteArray result, QByteArray result,
VoiceWaveform waveform, VoiceWaveform waveform,
int duration, int duration,
const SendOptions &options); const SendAction &action);
void sendFiles( void sendFiles(
Storage::PreparedList &&list, Storage::PreparedList &&list,
SendMediaType type, SendMediaType type,
TextWithTags &&caption, TextWithTags &&caption,
std::shared_ptr<SendingAlbum> album, std::shared_ptr<SendingAlbum> album,
const SendOptions &options); const SendAction &action);
void sendFile( void sendFile(
const QByteArray &fileContent, const QByteArray &fileContent,
SendMediaType type, SendMediaType type,
const SendOptions &options); const SendAction &action);
void editMedia( void editMedia(
Storage::PreparedList &&list, Storage::PreparedList &&list,
SendMediaType type, SendMediaType type,
TextWithTags &&caption, TextWithTags &&caption,
const SendOptions &options, const SendAction &action,
MsgId msgIdToEdit); MsgId msgIdToEdit);
void sendUploadedPhoto( void sendUploadedPhoto(
FullMsgId localId, FullMsgId localId,
const MTPInputFile &file, const MTPInputFile &file,
bool silent); Api::SendOptions options);
void sendUploadedDocument( void sendUploadedDocument(
FullMsgId localId, FullMsgId localId,
const MTPInputFile &file, const MTPInputFile &file,
const std::optional<MTPInputFile> &thumb, const std::optional<MTPInputFile> &thumb,
bool silent); Api::SendOptions options);
void editUploadedFile( void editUploadedFile(
FullMsgId localId, FullMsgId localId,
const MTPInputFile &file, const MTPInputFile &file,
const std::optional<MTPInputFile> &thumb, const std::optional<MTPInputFile> &thumb,
bool silent, Api::SendOptions options,
bool isDocument); bool isDocument);
void cancelLocalItem(not_null<HistoryItem*> item); void cancelLocalItem(not_null<HistoryItem*> item);
struct MessageToSend {
MessageToSend(not_null<History*> history);
not_null<History*> history;
TextWithTags textWithTags;
MsgId replyTo = 0;
WebPageId webPageId = 0;
bool silent = false;
bool clearDraft = true;
bool handleSupportSwitch = false;
};
void sendMessage(MessageToSend &&message); void sendMessage(MessageToSend &&message);
void sendBotStart(not_null<UserData*> bot, PeerData *chat = nullptr); void sendBotStart(not_null<UserData*> bot, PeerData *chat = nullptr);
void sendInlineResult( void sendInlineResult(
not_null<UserData*> bot, not_null<UserData*> bot,
not_null<InlineBots::Result*> data, not_null<InlineBots::Result*> data,
const SendOptions &options); const SendAction &action);
void sendMessageFail( void sendMessageFail(
const RPCError &error, const RPCError &error,
not_null<PeerData*> peer, not_null<PeerData*> peer,
@ -489,7 +471,7 @@ public:
void createPoll( void createPoll(
const PollData &data, const PollData &data,
const SendOptions &options, const SendAction &action,
FnMut<void()> done, FnMut<void()> done,
FnMut<void(const RPCError &error)> fail); FnMut<void(const RPCError &error)> fail);
void sendPollVotes( void sendPollVotes(
@ -634,7 +616,7 @@ private:
const QString &firstName, const QString &firstName,
const QString &lastName, const QString &lastName,
UserId userId, UserId userId,
const SendOptions &options); const SendAction &action);
void deleteHistory( void deleteHistory(
not_null<PeerData*> peer, not_null<PeerData*> peer,
@ -668,13 +650,13 @@ private:
void sendMedia( void sendMedia(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPInputMedia &media, const MTPInputMedia &media,
bool silent); Api::SendOptions options);
void sendMediaWithRandomId( void sendMediaWithRandomId(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPInputMedia &media, const MTPInputMedia &media,
bool silent, Api::SendOptions options,
uint64 randomId); uint64 randomId);
FileLoadTo fileLoadTaskOptions(const SendOptions &options) const; FileLoadTo fileLoadTaskOptions(const SendAction &action) const;
//void readFeeds(); // #feed //void readFeeds(); // #feed
@ -817,7 +799,7 @@ private:
not_null<Data::Folder*>, not_null<Data::Folder*>,
DialogsLoadState> _foldersLoadState; DialogsLoadState> _foldersLoadState;
rpl::event_stream<SendOptions> _sendActions; rpl::event_stream<SendAction> _sendActions;
struct ReadRequest { struct ReadRequest {
ReadRequest(mtpRequestId requestId, MsgId upTo) ReadRequest(mtpRequestId requestId, MsgId upTo)

View File

@ -920,7 +920,7 @@ void EditCaptionBox::save() {
std::move(_preparedList), std::move(_preparedList),
(!_asFile && _photo) ? SendMediaType::Photo : SendMediaType::File, (!_asFile && _photo) ? SendMediaType::Photo : SendMediaType::File,
_field->getTextWithAppliedMarkdown(), _field->getTextWithAppliedMarkdown(),
ApiWrap::SendOptions(item->history()), Api::SendAction(item->history()),
item->fullId().msg); item->fullId().msg);
closeBox(); closeBox();
return; return;

View File

@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lottie/lottie_single_player.h" #include "lottie/lottie_single_player.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "media/clip/media_clip_reader.h" #include "media/clip/media_clip_reader.h"
#include "api/api_common.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "layout.h" #include "layout.h"
#include "styles/style_history.h" #include "styles/style_history.h"
@ -1468,8 +1469,12 @@ void SendFilesBox::setupShadows(
} }
void SendFilesBox::prepare() { void SendFilesBox::prepare() {
_send = addButton(tr::lng_send_button(), [=] { send(); }); _send = addButton(tr::lng_send_button(), [=] { send({}); });
SetupSendWithoutSound(_send, [=] { return true; }, [=] { send(true); }); SetupSendWithoutSound(
_send,
[=] { return true; },
[=] { sendSilent(); },
[=] { sendScheduled(); });
addButton(tr::lng_cancel(), [=] { closeBox(); }); addButton(tr::lng_cancel(), [=] { closeBox(); });
initSendWay(); initSendWay();
setupCaption(); setupCaption();
@ -1638,7 +1643,7 @@ void SendFilesBox::setupCaption() {
const auto ctrlShiftEnter = modifiers.testFlag(Qt::ShiftModifier) const auto ctrlShiftEnter = modifiers.testFlag(Qt::ShiftModifier)
&& (modifiers.testFlag(Qt::ControlModifier) && (modifiers.testFlag(Qt::ControlModifier)
|| modifiers.testFlag(Qt::MetaModifier)); || modifiers.testFlag(Qt::MetaModifier));
send(false, ctrlShiftEnter); send({}, ctrlShiftEnter);
}); });
connect(_caption, &Ui::InputField::cancelled, [=] { closeBox(); }); connect(_caption, &Ui::InputField::cancelled, [=] { closeBox(); });
_caption->setMimeDataHook([=]( _caption->setMimeDataHook([=](
@ -1842,7 +1847,7 @@ void SendFilesBox::keyPressEvent(QKeyEvent *e) {
const auto ctrl = modifiers.testFlag(Qt::ControlModifier) const auto ctrl = modifiers.testFlag(Qt::ControlModifier)
|| modifiers.testFlag(Qt::MetaModifier); || modifiers.testFlag(Qt::MetaModifier);
const auto shift = modifiers.testFlag(Qt::ShiftModifier); const auto shift = modifiers.testFlag(Qt::ShiftModifier);
send(false, ctrl && shift); send({}, ctrl && shift);
} else { } else {
BoxContent::keyPressEvent(e); BoxContent::keyPressEvent(e);
} }
@ -1913,7 +1918,9 @@ void SendFilesBox::setInnerFocus() {
} }
} }
void SendFilesBox::send(bool silent, bool ctrlShiftEnter) { void SendFilesBox::send(
Api::SendOptions options,
bool ctrlShiftEnter) {
using Way = SendFilesWay; using Way = SendFilesWay;
const auto way = _sendWay ? _sendWay->value() : Way::Files; const auto way = _sendWay ? _sendWay->value() : Way::Files;
@ -1942,10 +1949,22 @@ void SendFilesBox::send(bool silent, bool ctrlShiftEnter) {
std::move(_list), std::move(_list),
way, way,
std::move(caption), std::move(caption),
silent, options,
ctrlShiftEnter); ctrlShiftEnter);
} }
closeBox(); closeBox();
} }
void SendFilesBox::sendSilent() {
auto options = Api::SendOptions();
options.silent = true;
send(options);
}
void SendFilesBox::sendScheduled() {
auto options = Api::SendOptions();
options.scheduled = INT_MAX;
send(options);
}
SendFilesBox::~SendFilesBox() = default; SendFilesBox::~SendFilesBox() = default;

View File

@ -16,6 +16,10 @@ namespace Window {
class SessionController; class SessionController;
} // namespace Window } // namespace Window
namespace Api {
struct SendOptions;
} // namespace Api
namespace ChatHelpers { namespace ChatHelpers {
class TabbedPanel; class TabbedPanel;
} // namespace ChatHelpers } // namespace ChatHelpers
@ -60,7 +64,7 @@ public:
Storage::PreparedList &&list, Storage::PreparedList &&list,
SendFilesWay way, SendFilesWay way,
TextWithTags &&caption, TextWithTags &&caption,
bool silent, Api::SendOptions options,
bool ctrlShiftEnter)> callback) { bool ctrlShiftEnter)> callback) {
_confirmedCallback = std::move(callback); _confirmedCallback = std::move(callback);
} }
@ -101,7 +105,9 @@ private:
void prepareAlbumPreview(); void prepareAlbumPreview();
void applyAlbumOrder(); void applyAlbumOrder();
void send(bool silent = false, bool ctrlShiftEnter = false); void send(Api::SendOptions options, bool ctrlShiftEnter = false);
void sendSilent();
void sendScheduled();
void captionResized(); void captionResized();
void setupTitleText(); void setupTitleText();
@ -128,7 +134,7 @@ private:
Storage::PreparedList &&list, Storage::PreparedList &&list,
SendFilesWay way, SendFilesWay way,
TextWithTags &&caption, TextWithTags &&caption,
bool silent, Api::SendOptions options,
bool ctrlShiftEnter)> _confirmedCallback; bool ctrlShiftEnter)> _confirmedCallback;
Fn<void()> _cancelledCallback; Fn<void()> _cancelledCallback;
bool _confirmed = false; bool _confirmed = false;

View File

@ -195,7 +195,7 @@ void ShareBox::prepareCommentField() {
const auto field = _comment->entity(); const auto field = _comment->entity();
connect(field, &Ui::InputField::submitted, [=] { connect(field, &Ui::InputField::submitted, [=] {
submit(); submit({});
}); });
field->setInstantReplaces(Ui::InstantReplaces::Default()); field->setInstantReplaces(Ui::InstantReplaces::Default());
@ -242,7 +242,7 @@ void ShareBox::prepare() {
_select->setSubmittedCallback([=](Qt::KeyboardModifiers modifiers) { _select->setSubmittedCallback([=](Qt::KeyboardModifiers modifiers) {
if (modifiers.testFlag(Qt::ControlModifier) if (modifiers.testFlag(Qt::ControlModifier)
|| modifiers.testFlag(Qt::MetaModifier)) { || modifiers.testFlag(Qt::MetaModifier)) {
submit(); submit({});
} else { } else {
_inner->selectActive(); _inner->selectActive();
} }
@ -412,12 +412,13 @@ void ShareBox::createButtons() {
clearButtons(); clearButtons();
if (_hasSelected) { if (_hasSelected) {
const auto send = addButton(tr::lng_share_confirm(), [=] { const auto send = addButton(tr::lng_share_confirm(), [=] {
submit(); submit({});
}); });
SetupSendWithoutSound( SetupSendWithoutSound(
send, send,
[=] { return true; }, [=] { return true; },
[=] { submit(true); }); [=] { submitSilent(); },
[=] { submitScheduled(); });
} else if (_copyCallback) { } else if (_copyCallback) {
addButton(tr::lng_share_copy_link(), [=] { copyLink(); }); addButton(tr::lng_share_copy_link(), [=] { copyLink(); });
} }
@ -451,15 +452,27 @@ void ShareBox::innerSelectedChanged(PeerData *peer, bool checked) {
update(); update();
} }
void ShareBox::submit(bool silent) { void ShareBox::submit(Api::SendOptions options) {
if (_submitCallback) { if (_submitCallback) {
_submitCallback( _submitCallback(
_inner->selected(), _inner->selected(),
_comment->entity()->getTextWithAppliedMarkdown(), _comment->entity()->getTextWithAppliedMarkdown(),
silent); options);
} }
} }
void ShareBox::submitSilent() {
auto options = Api::SendOptions();
options.silent = true;
submit(options);
}
void ShareBox::submitScheduled() {
auto options = Api::SendOptions();
options.scheduled = INT_MAX;
submit(options);
}
void ShareBox::copyLink() { void ShareBox::copyLink() {
if (_copyCallback) { if (_copyCallback) {
_copyCallback(); _copyCallback();

View File

@ -17,6 +17,10 @@ namespace Window {
class SessionNavigation; class SessionNavigation;
} // namespace Window } // namespace Window
namespace Api {
struct SendOptions;
} // namespace Api
namespace Main { namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
@ -52,7 +56,7 @@ public:
using SubmitCallback = Fn<void( using SubmitCallback = Fn<void(
QVector<PeerData*>&&, QVector<PeerData*>&&,
TextWithTags&&, TextWithTags&&,
bool)>; Api::SendOptions)>;
using FilterCallback = Fn<bool(PeerData*)>; using FilterCallback = Fn<bool(PeerData*)>;
ShareBox( ShareBox(
@ -73,7 +77,9 @@ private:
void prepareCommentField(); void prepareCommentField();
void scrollAnimationCallback(); void scrollAnimationCallback();
void submit(bool silent = false); void submit(Api::SendOptions options);
void submitSilent();
void submitScheduled();
void copyLink(); void copyLink();
bool searchByUsername(bool useCache = false); bool searchByUsername(bool useCache = false);

View File

@ -787,13 +787,25 @@ void MessageLinksParser::apply(
void SetupSendWithoutSound( void SetupSendWithoutSound(
not_null<Ui::RpWidget*> button, not_null<Ui::RpWidget*> button,
Fn<bool()> enabled, Fn<bool()> enabled,
Fn<void()> send) { Fn<void()> send,
Fn<void()> schedule) {
if (!send && !schedule) {
return;
}
const auto menu = std::make_shared<base::unique_qptr<Ui::PopupMenu>>(); const auto menu = std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
const auto showMenu = [=] {
*menu = base::make_unique_q<Ui::PopupMenu>(button);
if (send) {
(*menu)->addAction(tr::lng_send_silent_message(tr::now), send);
}
if (schedule) {
(*menu)->addAction(tr::lng_schedule_message(tr::now), schedule);
}
(*menu)->popup(QCursor::pos());
};
Core::InstallEventFilter(button, [=](not_null<QEvent*> e) { Core::InstallEventFilter(button, [=](not_null<QEvent*> e) {
if (e->type() == QEvent::ContextMenu && enabled()) { if (e->type() == QEvent::ContextMenu && enabled()) {
*menu = base::make_unique_q<Ui::PopupMenu>(button); showMenu();
(*menu)->addAction(tr::lng_send_silent_message(tr::now), send);
(*menu)->popup(QCursor::pos());
return true; return true;
} }
return false; return false;

View File

@ -109,4 +109,5 @@ private:
void SetupSendWithoutSound( void SetupSendWithoutSound(
not_null<Ui::RpWidget*> button, not_null<Ui::RpWidget*> button,
Fn<bool()> enabled, Fn<bool()> enabled,
Fn<void()> send); Fn<void()> send,
Fn<void()> schedule);

View File

@ -113,11 +113,11 @@ void activateBotCommand(
const auto history = msg->history(); const auto history = msg->history();
Ui::show(Box<ConfirmBox>(tr::lng_bot_share_phone(tr::now), tr::lng_bot_share_phone_confirm(tr::now), [=] { Ui::show(Box<ConfirmBox>(tr::lng_bot_share_phone(tr::now), tr::lng_bot_share_phone_confirm(tr::now), [=] {
Ui::showPeerHistory(history, ShowAtTheEndMsgId); Ui::showPeerHistory(history, ShowAtTheEndMsgId);
auto options = ApiWrap::SendOptions(history); auto action = Api::SendAction(history);
options.replyTo = msgId; action.replyTo = msgId;
history->session().api().shareContact( history->session().api().shareContact(
history->session().user(), history->session().user(),
options); action);
})); }));
} break; } break;

View File

@ -223,7 +223,7 @@ void FastShareMessage(not_null<HistoryItem*> item) {
auto submitCallback = [=]( auto submitCallback = [=](
QVector<PeerData*> &&result, QVector<PeerData*> &&result,
TextWithTags &&comment, TextWithTags &&comment,
bool silent) { Api::SendOptions options) {
if (!data->requests.empty()) { if (!data->requests.empty()) {
return; // Share clicked already. return; // Share clicked already.
} }
@ -272,7 +272,7 @@ void FastShareMessage(not_null<HistoryItem*> item) {
| (isGroup | (isGroup
? MTPmessages_ForwardMessages::Flag::f_grouped ? MTPmessages_ForwardMessages::Flag::f_grouped
: MTPmessages_ForwardMessages::Flag(0)) : MTPmessages_ForwardMessages::Flag(0))
| (silent | (options.silent
? MTPmessages_ForwardMessages::Flag::f_silent ? MTPmessages_ForwardMessages::Flag::f_silent
: MTPmessages_ForwardMessages::Flag(0)); : MTPmessages_ForwardMessages::Flag(0));
auto msgIds = QVector<MTPint>(); auto msgIds = QVector<MTPint>();
@ -292,7 +292,7 @@ void FastShareMessage(not_null<HistoryItem*> item) {
if (!comment.text.isEmpty()) { if (!comment.text.isEmpty()) {
auto message = ApiWrap::MessageToSend(history); auto message = ApiWrap::MessageToSend(history);
message.textWithTags = comment; message.textWithTags = comment;
message.clearDraft = false; message.action.clearDraft = false;
history->session().api().sendMessage(std::move(message)); history->session().api().sendMessage(std::move(message));
} }
history->sendRequestId = MTP::send( history->sendRequestId = MTP::send(

View File

@ -309,7 +309,7 @@ HistoryWidget::HistoryWidget(
SetupSendWithoutSound(_send, [=] { SetupSendWithoutSound(_send, [=] {
return (_send->type() == Ui::SendButton::Type::Send) return (_send->type() == Ui::SendButton::Type::Send)
&& !_send->isDisabled(); && !_send->isDisabled();
}, [=] { send(true); }); }, [=] { sendSilent(); }, [=] { sendScheduled(); });
_unblock->addClickHandler([=] { unblockUser(); }); _unblock->addClickHandler([=] { unblockUser(); });
_botStart->addClickHandler([=] { sendBotStartCommand(); }); _botStart->addClickHandler([=] { sendBotStartCommand(); });
_joinChannel->addClickHandler([=] { joinChannel(); }); _joinChannel->addClickHandler([=] { joinChannel(); });
@ -318,7 +318,7 @@ HistoryWidget::HistoryWidget(
connect( connect(
_field, _field,
&Ui::InputField::submitted, &Ui::InputField::submitted,
[=](Qt::KeyboardModifiers modifiers) { send(false, modifiers); }); [=](Qt::KeyboardModifiers modifiers) { sendWithModifiers(modifiers); });
connect(_field, &Ui::InputField::cancelled, [=] { connect(_field, &Ui::InputField::cancelled, [=] {
escape(); escape();
}); });
@ -631,18 +631,18 @@ HistoryWidget::HistoryWidget(
}, _topBar->lifetime()); }, _topBar->lifetime());
session().api().sendActions( session().api().sendActions(
) | rpl::filter([=](const ApiWrap::SendOptions &options) { ) | rpl::filter([=](const Api::SendAction &action) {
return (options.history == _history); return (action.history == _history);
}) | rpl::start_with_next([=](const ApiWrap::SendOptions &options) { }) | rpl::start_with_next([=](const Api::SendAction &action) {
fastShowAtEnd(options.history); fastShowAtEnd(action.history);
const auto lastKeyboardUsed = lastForceReplyReplied(FullMsgId( const auto lastKeyboardUsed = lastForceReplyReplied(FullMsgId(
options.history->channelId(), action.history->channelId(),
options.replyTo)); action.replyTo));
if (cancelReply(lastKeyboardUsed) && !options.clearDraft) { if (cancelReply(lastKeyboardUsed) && !action.clearDraft) {
onCloudDraftSave(); onCloudDraftSave();
} }
if (options.handleSupportSwitch) { if (action.options.handleSupportSwitch) {
handleSupportSwitch(options.history); handleSupportSwitch(action.history);
} }
}, lifetime()); }, lifetime());
@ -705,14 +705,16 @@ void HistoryWidget::supportShareContact(Support::Contact contact) {
if (!history) { if (!history) {
return; return;
} }
send(false, Support::SkipSwitchModifiers()); auto options = Api::SendOptions();
auto options = ApiWrap::SendOptions(history); auto action = Api::SendAction(history);
send(options);
options.handleSupportSwitch = Support::HandleSwitch(modifiers); options.handleSupportSwitch = Support::HandleSwitch(modifiers);
action.options = options;
session().api().shareContact( session().api().shareContact(
contact.phone, contact.phone,
contact.firstName, contact.firstName,
contact.lastName, contact.lastName,
options); action);
}; };
const auto box = Ui::show(Box<Support::ConfirmContactBox>( const auto box = Ui::show(Box<Support::ConfirmContactBox>(
_history, _history,
@ -978,7 +980,7 @@ void HistoryWidget::onHashtagOrBotCommandInsert(
// Send bot command at once, if it was not inserted by pressing Tab. // Send bot command at once, if it was not inserted by pressing Tab.
if (str.at(0) == '/' && method != FieldAutocomplete::ChooseMethod::ByTab) { if (str.at(0) == '/' && method != FieldAutocomplete::ChooseMethod::ByTab) {
App::sendBotCommand(_peer, nullptr, str, replyToId()); App::sendBotCommand(_peer, nullptr, str, replyToId());
App::main()->finishForwarding(_history, false); App::main()->finishForwarding(Api::SendAction(_history));
setFieldText(_field->getTextWithTagsPart(_field->textCursor().position())); setFieldText(_field->getTextWithTagsPart(_field->textCursor().position()));
} else { } else {
_field->insertTag(str); _field->insertTag(str);
@ -1336,9 +1338,9 @@ void HistoryWidget::onRecordDone(
ActivateWindow(controller()); ActivateWindow(controller());
const auto duration = samples / Media::Player::kDefaultFrequency; const auto duration = samples / Media::Player::kDefaultFrequency;
auto options = ApiWrap::SendOptions(_history); auto action = Api::SendAction(_history);
options.replyTo = replyToId(); action.replyTo = replyToId();
session().api().sendVoiceMessage(result, waveform, duration, options); session().api().sendVoiceMessage(result, waveform, duration, action);
} }
void HistoryWidget::onRecordUpdate(quint16 level, qint32 samples) { void HistoryWidget::onRecordUpdate(quint16 level, qint32 samples) {
@ -2887,7 +2889,7 @@ void HistoryWidget::hideSelectorControlsAnimated() {
} }
} }
void HistoryWidget::send(bool silent, Qt::KeyboardModifiers modifiers) { void HistoryWidget::send(Api::SendOptions options) {
if (!_history) { if (!_history) {
return; return;
} else if (_editMsgId) { } else if (_editMsgId) {
@ -2905,10 +2907,9 @@ void HistoryWidget::send(bool silent, Qt::KeyboardModifiers modifiers) {
auto message = ApiWrap::MessageToSend(_history); auto message = ApiWrap::MessageToSend(_history);
message.textWithTags = _field->getTextWithAppliedMarkdown(); message.textWithTags = _field->getTextWithAppliedMarkdown();
message.replyTo = replyToId(); message.action.options = options;
message.action.replyTo = replyToId();
message.webPageId = webPageId; message.webPageId = webPageId;
message.silent = silent;
message.handleSupportSwitch = Support::HandleSwitch(modifiers);
if (_canSendMessages) { if (_canSendMessages) {
const auto error = GetErrorTextForForward( const auto error = GetErrorTextForForward(
@ -2938,6 +2939,24 @@ void HistoryWidget::send(bool silent, Qt::KeyboardModifiers modifiers) {
} }
} }
void HistoryWidget::sendWithModifiers(Qt::KeyboardModifiers modifiers) {
auto options = Api::SendOptions();
options.handleSupportSwitch = Support::HandleSwitch(modifiers);
send(options);
}
void HistoryWidget::sendSilent() {
auto options = Api::SendOptions();
options.silent = true;
send(options);
}
void HistoryWidget::sendScheduled() {
auto options = Api::SendOptions();
options.scheduled = INT_MAX;
send(options);
}
void HistoryWidget::unblockUser() { void HistoryWidget::unblockUser() {
if (const auto user = _peer ? _peer->asUser() : nullptr) { if (const auto user = _peer ? _peer->asUser() : nullptr) {
Window::PeerMenuUnblockUserWithBotRestart(user); Window::PeerMenuUnblockUserWithBotRestart(user);
@ -3169,7 +3188,7 @@ void HistoryWidget::sendButtonClicked() {
if (type == Ui::SendButton::Type::Cancel) { if (type == Ui::SendButton::Type::Cancel) {
onInlineBotCancel(); onInlineBotCancel();
} else if (type != Ui::SendButton::Type::Record) { } else if (type != Ui::SendButton::Type::Record) {
send(); send({});
} }
} }
@ -3316,7 +3335,7 @@ void HistoryWidget::sendBotCommand(PeerData *peer, UserData *bot, const QString
auto message = ApiWrap::MessageToSend(_history); auto message = ApiWrap::MessageToSend(_history);
message.textWithTags = { toSend, TextWithTags::Tags() }; message.textWithTags = { toSend, TextWithTags::Tags() };
message.replyTo = replyTo message.action.replyTo = replyTo
? ((!_peer->isUser()/* && (botStatus == 0 || botStatus == 2)*/) ? ((!_peer->isUser()/* && (botStatus == 0 || botStatus == 2)*/)
? replyTo ? replyTo
: replyToId()) : replyToId())
@ -4163,7 +4182,7 @@ bool HistoryWidget::confirmSendingFiles(
Storage::PreparedList &&list, Storage::PreparedList &&list,
SendFilesWay way, SendFilesWay way,
TextWithTags &&caption, TextWithTags &&caption,
bool silent, Api::SendOptions options,
bool ctrlShiftEnter) { bool ctrlShiftEnter) {
if (showSendingFilesError(list)) { if (showSendingFilesError(list)) {
return; return;
@ -4179,7 +4198,7 @@ bool HistoryWidget::confirmSendingFiles(
type, type,
std::move(caption), std::move(caption),
replyToId(), replyToId(),
silent, options,
album); album);
})); }));
box->setCancelledCallback(crl::guard(this, [=] { box->setCancelledCallback(crl::guard(this, [=] {
@ -4288,7 +4307,7 @@ void HistoryWidget::uploadFilesAfterConfirmation(
SendMediaType type, SendMediaType type,
TextWithTags &&caption, TextWithTags &&caption,
MsgId replyTo, MsgId replyTo,
bool silent, Api::SendOptions options,
std::shared_ptr<SendingAlbum> album) { std::shared_ptr<SendingAlbum> album) {
Assert(canWriteMessage()); Assert(canWriteMessage());
@ -4303,15 +4322,15 @@ void HistoryWidget::uploadFilesAfterConfirmation(
return; return;
} }
auto options = ApiWrap::SendOptions(_history); auto action = Api::SendAction(_history);
options.replyTo = replyTo; action.replyTo = replyTo;
options.silent = silent; action.options = options;
session().api().sendFiles( session().api().sendFiles(
std::move(list), std::move(list),
type, type,
std::move(caption), std::move(caption),
album, album,
options); action);
} }
void HistoryWidget::uploadFile( void HistoryWidget::uploadFile(
@ -4319,9 +4338,9 @@ void HistoryWidget::uploadFile(
SendMediaType type) { SendMediaType type) {
if (!canWriteMessage()) return; if (!canWriteMessage()) return;
auto options = ApiWrap::SendOptions(_history); auto action = Api::SendAction(_history);
options.replyTo = replyToId(); action.replyTo = replyToId();
session().api().sendFile(fileContent, type, options); session().api().sendFile(fileContent, type, action);
} }
void HistoryWidget::subscribeToUploader() { void HistoryWidget::subscribeToUploader() {
@ -4331,9 +4350,11 @@ void HistoryWidget::subscribeToUploader() {
using namespace Storage; using namespace Storage;
session().uploader().photoReady( session().uploader().photoReady(
) | rpl::start_with_next([=](const UploadedPhoto &data) { ) | rpl::start_with_next([=](const UploadedPhoto &data) {
data.edit if (data.edit) {
? photoEdited(data.fullId, data.silent, data.file) photoEdited(data.fullId, data.options, data.file);
: photoUploaded(data.fullId, data.silent, data.file); } else {
photoUploaded(data.fullId, data.options, data.file);
}
}, _uploaderSubscriptions); }, _uploaderSubscriptions);
session().uploader().photoProgress( session().uploader().photoProgress(
) | rpl::start_with_next([=](const FullMsgId &fullId) { ) | rpl::start_with_next([=](const FullMsgId &fullId) {
@ -4345,15 +4366,17 @@ void HistoryWidget::subscribeToUploader() {
}, _uploaderSubscriptions); }, _uploaderSubscriptions);
session().uploader().documentReady( session().uploader().documentReady(
) | rpl::start_with_next([=](const UploadedDocument &data) { ) | rpl::start_with_next([=](const UploadedDocument &data) {
data.edit if (data.edit) {
? documentEdited(data.fullId, data.silent, data.file) documentEdited(data.fullId, data.options, data.file);
: documentUploaded(data.fullId, data.silent, data.file); } else {
documentUploaded(data.fullId, data.options, data.file);
}
}, _uploaderSubscriptions); }, _uploaderSubscriptions);
session().uploader().thumbDocumentReady( session().uploader().thumbDocumentReady(
) | rpl::start_with_next([=](const UploadedThumbDocument &data) { ) | rpl::start_with_next([=](const UploadedThumbDocument &data) {
thumbDocumentUploaded( thumbDocumentUploaded(
data.fullId, data.fullId,
data.silent, data.options,
data.file, data.file,
data.thumb, data.thumb,
data.edit); data.edit);
@ -4399,11 +4422,11 @@ void HistoryWidget::sendFileConfirmed(
const auto history = session().data().history(file->to.peer); const auto history = session().data().history(file->to.peer);
const auto peer = history->peer; const auto peer = history->peer;
auto options = ApiWrap::SendOptions(history); auto action = Api::SendAction(history);
options.clearDraft = false; action.clearDraft = false;
options.replyTo = file->to.replyTo; action.replyTo = file->to.replyTo;
options.generateLocal = true; action.generateLocal = true;
session().api().sendAction(options); session().api().sendAction(action);
auto caption = TextWithEntities{ auto caption = TextWithEntities{
file->caption.text, file->caption.text,
@ -4430,7 +4453,7 @@ void HistoryWidget::sendFileConfirmed(
flags |= MTPDmessage::Flag::f_reply_to_msg_id; flags |= MTPDmessage::Flag::f_reply_to_msg_id;
} }
const auto channelPost = peer->isChannel() && !peer->isMegagroup(); const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = file->to.silent; const auto silentPost = file->to.options.silent;
if (channelPost) { if (channelPost) {
flags |= MTPDmessage::Flag::f_views; flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post; flags |= MTPDmessage::Flag::f_post;
@ -4572,41 +4595,43 @@ void HistoryWidget::sendFileConfirmed(
void HistoryWidget::photoUploaded( void HistoryWidget::photoUploaded(
const FullMsgId &newId, const FullMsgId &newId,
bool silent, Api::SendOptions options,
const MTPInputFile &file) { const MTPInputFile &file) {
session().api().sendUploadedPhoto(newId, file, silent); session().api().sendUploadedPhoto(newId, file, options);
} }
void HistoryWidget::documentUploaded( void HistoryWidget::documentUploaded(
const FullMsgId &newId, const FullMsgId &newId,
bool silent, Api::SendOptions options,
const MTPInputFile &file) { const MTPInputFile &file) {
session().api().sendUploadedDocument(newId, file, std::nullopt, silent); session().api().sendUploadedDocument(newId, file, std::nullopt, options);
} }
void HistoryWidget::documentEdited( void HistoryWidget::documentEdited(
const FullMsgId &newId, const FullMsgId &newId,
bool silent, Api::SendOptions options,
const MTPInputFile &file) { const MTPInputFile &file) {
session().api().editUploadedFile(newId, file, std::nullopt, silent, true); session().api().editUploadedFile(newId, file, std::nullopt, options, true);
} }
void HistoryWidget::photoEdited( void HistoryWidget::photoEdited(
const FullMsgId &newId, const FullMsgId &newId,
bool silent, Api::SendOptions options,
const MTPInputFile &file) { const MTPInputFile &file) {
session().api().editUploadedFile(newId, file, std::nullopt, silent, false); session().api().editUploadedFile(newId, file, std::nullopt, options, false);
} }
void HistoryWidget::thumbDocumentUploaded( void HistoryWidget::thumbDocumentUploaded(
const FullMsgId &newId, const FullMsgId &newId,
bool silent, Api::SendOptions options,
const MTPInputFile &file, const MTPInputFile &file,
const MTPInputFile &thumb, const MTPInputFile &thumb,
bool edit) { bool edit) {
edit if (edit) {
? session().api().editUploadedFile(newId, file, thumb, silent, true) session().api().editUploadedFile(newId, file, thumb, options, true);
: session().api().sendUploadedDocument(newId, file, thumb, silent); } else {
session().api().sendUploadedDocument(newId, file, thumb, options);
}
} }
void HistoryWidget::photoProgress(const FullMsgId &newId) { void HistoryWidget::photoProgress(const FullMsgId &newId) {
@ -5349,7 +5374,7 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) {
session().settings().sendSubmitWay(), session().settings().sendSubmitWay(),
e->modifiers()); e->modifiers());
if (submitting) { if (submitting) {
send(false, e->modifiers()); sendWithModifiers(e->modifiers());
} }
} }
} else if (e->key() == Qt::Key_O && e->modifiers() == Qt::ControlModifier) { } else if (e->key() == Qt::Key_O && e->modifiers() == Qt::ControlModifier) {
@ -5478,11 +5503,11 @@ void HistoryWidget::sendInlineResult(
return; return;
} }
auto options = ApiWrap::SendOptions(_history); auto action = Api::SendAction(_history);
options.clearDraft = true; action.clearDraft = true;
options.replyTo = replyToId(); action.replyTo = replyToId();
options.generateLocal = true; action.generateLocal = true;
session().api().sendInlineResult(bot, result, options); session().api().sendInlineResult(bot, result, action);
clearFieldText(); clearFieldText();
_saveDraftText = true; _saveDraftText = true;
@ -5612,9 +5637,7 @@ void HistoryWidget::destroyPinnedBar() {
_inPinnedMsg = false; _inPinnedMsg = false;
} }
bool HistoryWidget::sendExistingDocument( bool HistoryWidget::sendExistingDocument(not_null<DocumentData*> document) {
not_null<DocumentData*> document,
TextWithEntities caption) {
const auto error = _peer const auto error = _peer
? Data::RestrictionError(_peer, ChatRestriction::f_send_stickers) ? Data::RestrictionError(_peer, ChatRestriction::f_send_stickers)
: std::nullopt; : std::nullopt;
@ -5627,7 +5650,9 @@ bool HistoryWidget::sendExistingDocument(
return false; return false;
} }
Api::SendExistingDocument(_history, document, caption, replyToId()); auto message = Api::MessageToSend(_history);
message.action.replyTo = replyToId();
Api::SendExistingDocument(std::move(message), document);
if (_fieldAutocomplete->stickersShown()) { if (_fieldAutocomplete->stickersShown()) {
clearFieldText(); clearFieldText();
@ -5643,9 +5668,7 @@ bool HistoryWidget::sendExistingDocument(
return true; return true;
} }
bool HistoryWidget::sendExistingPhoto( bool HistoryWidget::sendExistingPhoto(not_null<PhotoData*> photo) {
not_null<PhotoData*> photo,
TextWithEntities caption) {
const auto error = _peer const auto error = _peer
? Data::RestrictionError(_peer, ChatRestriction::f_send_media) ? Data::RestrictionError(_peer, ChatRestriction::f_send_media)
: std::nullopt; : std::nullopt;
@ -5658,7 +5681,9 @@ bool HistoryWidget::sendExistingPhoto(
return false; return false;
} }
Api::SendExistingPhoto(_history, photo, caption, replyToId()); auto message = Api::MessageToSend(_history);
message.action.replyTo = replyToId();
Api::SendExistingPhoto(std::move(message), photo);
hideSelectorControlsAnimated(); hideSelectorControlsAnimated();

View File

@ -24,6 +24,10 @@ enum class SendMediaType;
enum class CompressConfirm; enum class CompressConfirm;
class MessageLinksParser; class MessageLinksParser;
namespace Api {
struct SendOptions;
} // namespace Api
namespace InlineBots { namespace InlineBots {
namespace Layout { namespace Layout {
class ItemBase; class ItemBase;
@ -237,12 +241,8 @@ public:
void confirmDeleteSelected(); void confirmDeleteSelected();
void clearSelected(); void clearSelected();
bool sendExistingDocument( bool sendExistingDocument(not_null<DocumentData*> document);
not_null<DocumentData*> document, bool sendExistingPhoto(not_null<PhotoData*> photo);
TextWithEntities caption = TextWithEntities());
bool sendExistingPhoto(
not_null<PhotoData*> photo,
TextWithEntities caption = TextWithEntities());
// Float player interface. // Float player interface.
bool wheelEventFromFloatPlayer(QEvent *e) override; bool wheelEventFromFloatPlayer(QEvent *e) override;
@ -324,9 +324,10 @@ private:
void initTabbedSelector(); void initTabbedSelector();
void updateField(); void updateField();
void send( void send(Api::SendOptions options);
bool silent = false, void sendWithModifiers(Qt::KeyboardModifiers modifiers);
Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers()); void sendSilent();
void sendScheduled();
void handlePendingHistoryUpdate(); void handlePendingHistoryUpdate();
void fullPeerUpdated(PeerData *peer); void fullPeerUpdated(PeerData *peer);
void toggleTabbedSelectorMode(); void toggleTabbedSelectorMode();
@ -410,24 +411,24 @@ private:
SendMediaType type, SendMediaType type,
TextWithTags &&caption, TextWithTags &&caption,
MsgId replyTo, MsgId replyTo,
bool silent, Api::SendOptions options,
std::shared_ptr<SendingAlbum> album = nullptr); std::shared_ptr<SendingAlbum> album = nullptr);
void subscribeToUploader(); void subscribeToUploader();
void photoUploaded( void photoUploaded(
const FullMsgId &msgId, const FullMsgId &msgId,
bool silent, Api::SendOptions options,
const MTPInputFile &file); const MTPInputFile &file);
void photoProgress(const FullMsgId &msgId); void photoProgress(const FullMsgId &msgId);
void photoFailed(const FullMsgId &msgId); void photoFailed(const FullMsgId &msgId);
void documentUploaded( void documentUploaded(
const FullMsgId &msgId, const FullMsgId &msgId,
bool silent, Api::SendOptions options,
const MTPInputFile &file); const MTPInputFile &file);
void thumbDocumentUploaded( void thumbDocumentUploaded(
const FullMsgId &msgId, const FullMsgId &msgId,
bool silent, Api::SendOptions options,
const MTPInputFile &file, const MTPInputFile &file,
const MTPInputFile &thumb, const MTPInputFile &thumb,
bool edit = false); bool edit = false);
@ -436,12 +437,12 @@ private:
void documentEdited( void documentEdited(
const FullMsgId &msgId, const FullMsgId &msgId,
bool silent, Api::SendOptions options,
const MTPInputFile &file); const MTPInputFile &file);
void photoEdited( void photoEdited(
const FullMsgId &msgId, const FullMsgId &msgId,
bool silent, Api::SendOptions options,
const MTPInputFile &file); const MTPInputFile &file);
void itemRemoved(not_null<const HistoryItem*> item); void itemRemoved(not_null<const HistoryItem*> item);

View File

@ -680,7 +680,8 @@ void MainWidget::cancelForwarding(not_null<History*> history) {
_history->updateForwarding(); _history->updateForwarding();
} }
void MainWidget::finishForwarding(not_null<History*> history, bool silent) { void MainWidget::finishForwarding(Api::SendAction action) {
const auto history = action.history;
auto toForward = history->validateForwardDraft(); auto toForward = history->validateForwardDraft();
if (!toForward.empty()) { if (!toForward.empty()) {
const auto error = GetErrorTextForForward(history->peer, toForward); const auto error = GetErrorTextForForward(history->peer, toForward);
@ -688,9 +689,7 @@ void MainWidget::finishForwarding(not_null<History*> history, bool silent) {
return; return;
} }
auto options = ApiWrap::SendOptions(history); session().api().forwardMessages(std::move(toForward), action);
options.silent = silent;
session().api().forwardMessages(std::move(toForward), options);
cancelForwarding(history); cancelForwarding(history);
} }

View File

@ -21,6 +21,10 @@ class HistoryWidget;
class StackItem; class StackItem;
struct FileLoadResult; struct FileLoadResult;
namespace Api {
struct SendAction;
} // namespace Api
namespace Main { namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
@ -231,7 +235,7 @@ public:
void pushReplyReturn(not_null<HistoryItem*> item); void pushReplyReturn(not_null<HistoryItem*> item);
void cancelForwarding(not_null<History*> history); void cancelForwarding(not_null<History*> history);
void finishForwarding(not_null<History*> history, bool silent); void finishForwarding(Api::SendAction action);
// Does offerPeer or showPeerHistory. // Does offerPeer or showPeerHistory.
void choosePeer(PeerId peerId, MsgId showAtMsgId); void choosePeer(PeerId peerId, MsgId showAtMsgId);

View File

@ -1510,7 +1510,7 @@ void FormController::uploadEncryptedFile(
auto prepared = std::make_shared<FileLoadResult>( auto prepared = std::make_shared<FileLoadResult>(
TaskId(), TaskId(),
file.uploadData->fileId, file.uploadData->fileId,
FileLoadTo(PeerId(0), false, MsgId(0)), FileLoadTo(PeerId(0), Api::SendOptions(), MsgId(0)),
TextWithTags(), TextWithTags(),
std::shared_ptr<SendingAlbum>(nullptr)); std::shared_ptr<SendingAlbum>(nullptr));
prepared->type = SendMediaType::Secure; prepared->type = SendMediaType::Secure;

View File

@ -312,8 +312,9 @@ void Uploader::sendNext() {
if (parts.isEmpty()) { if (parts.isEmpty()) {
if (uploadingData.docSentParts >= uploadingData.docPartsCount) { if (uploadingData.docSentParts >= uploadingData.docPartsCount) {
if (requestsSent.empty() && docRequestsSent.empty()) { if (requestsSent.empty() && docRequestsSent.empty()) {
const auto silent = uploadingData.file const auto options = uploadingData.file
&& uploadingData.file->to.silent; ? uploadingData.file->to.options
: Api::SendOptions();
const auto edit = uploadingData.file && const auto edit = uploadingData.file &&
uploadingData.file->edit; uploadingData.file->edit;
if (uploadingData.type() == SendMediaType::Photo) { if (uploadingData.type() == SendMediaType::Photo) {
@ -332,7 +333,7 @@ void Uploader::sendNext() {
MTP_int(uploadingData.partsCount), MTP_int(uploadingData.partsCount),
MTP_string(photoFilename), MTP_string(photoFilename),
MTP_bytes(md5)); MTP_bytes(md5));
_photoReady.fire({ uploadingId, silent, file, edit }); _photoReady.fire({ uploadingId, options, file, edit });
} else if (uploadingData.type() == SendMediaType::File } else if (uploadingData.type() == SendMediaType::File
|| uploadingData.type() == SendMediaType::WallPaper || uploadingData.type() == SendMediaType::WallPaper
|| uploadingData.type() == SendMediaType::Audio) { || uploadingData.type() == SendMediaType::Audio) {
@ -363,14 +364,14 @@ void Uploader::sendNext() {
MTP_bytes(thumbMd5)); MTP_bytes(thumbMd5));
_thumbDocumentReady.fire({ _thumbDocumentReady.fire({
uploadingId, uploadingId,
silent, options,
file, file,
thumb, thumb,
edit }); edit });
} else { } else {
_documentReady.fire({ _documentReady.fire({
uploadingId, uploadingId,
silent, options,
file, file,
edit }); edit });
} }

View File

@ -7,9 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "api/api_common.h"
class ApiWrap;
struct FileLoadResult; struct FileLoadResult;
struct SendMediaReady; struct SendMediaReady;
class ApiWrap;
namespace Storage { namespace Storage {
@ -18,21 +20,21 @@ constexpr auto kUseBigFilesFrom = 10 * 1024 * 1024;
struct UploadedPhoto { struct UploadedPhoto {
FullMsgId fullId; FullMsgId fullId;
bool silent = false; Api::SendOptions options;
MTPInputFile file; MTPInputFile file;
bool edit = false; bool edit = false;
}; };
struct UploadedDocument { struct UploadedDocument {
FullMsgId fullId; FullMsgId fullId;
bool silent = false; Api::SendOptions options;
MTPInputFile file; MTPInputFile file;
bool edit = false; bool edit = false;
}; };
struct UploadedThumbDocument { struct UploadedThumbDocument {
FullMsgId fullId; FullMsgId fullId;
bool silent = false; Api::SendOptions options;
MTPInputFile file; MTPInputFile file;
MTPInputFile thumb; MTPInputFile thumb;
bool edit = false; bool edit = false;

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "base/variant.h" #include "base/variant.h"
#include "api/api_common.h"
enum class CompressConfirm { enum class CompressConfirm {
Auto, Auto,
@ -175,18 +176,18 @@ struct SendingAlbum {
uint64 groupId = 0; uint64 groupId = 0;
std::vector<Item> items; std::vector<Item> items;
bool silent = false; Api::SendOptions options;
}; };
struct FileLoadTo { struct FileLoadTo {
FileLoadTo(const PeerId &peer, bool silent, MsgId replyTo) FileLoadTo(const PeerId &peer, Api::SendOptions options, MsgId replyTo)
: peer(peer) : peer(peer)
, silent(silent) , options(options)
, replyTo(replyTo) { , replyTo(replyTo) {
} }
PeerId peer; PeerId peer;
bool silent; Api::SendOptions options;
MsgId replyTo; MsgId replyTo;
}; };

View File

@ -609,7 +609,7 @@ QString InterpretSendPath(const QString &path) {
SendMediaType::File, SendMediaType::File,
{ caption }, { caption },
nullptr, nullptr,
ApiWrap::SendOptions(history)); Api::SendAction(history));
return QString(); return QString();
} }

View File

@ -512,10 +512,10 @@ void Manager::notificationReplied(
const auto history = system()->session().data().history(peerId); const auto history = system()->session().data().history(peerId);
auto message = ApiWrap::MessageToSend(history); auto message = Api::MessageToSend(history);
message.textWithTags = reply; message.textWithTags = reply;
message.replyTo = (msgId > 0 && !history->peer->isUser()) ? msgId : 0; message.action.replyTo = (msgId > 0 && !history->peer->isUser()) ? msgId : 0;
message.clearDraft = false; message.action.clearDraft = false;
history->session().api().sendMessage(std::move(message)); history->session().api().sendMessage(std::move(message));
const auto item = history->owner().message(history->channelId(), msgId); const auto item = history->owner().message(history->channelId(), msgId);

View File

@ -667,8 +667,8 @@ void PeerMenuShareContactBox(
LayerOption::KeepOther); LayerOption::KeepOther);
return; return;
} else if (peer->isSelf()) { } else if (peer->isSelf()) {
auto options = ApiWrap::SendOptions(peer->owner().history(peer)); auto action = Api::SendAction(peer->owner().history(peer));
user->session().api().shareContact(user, options); user->session().api().shareContact(user, action);
Ui::Toast::Show(tr::lng_share_done(tr::now)); Ui::Toast::Show(tr::lng_share_done(tr::now));
if (auto strong = *weak) { if (auto strong = *weak) {
strong->closeBox(); strong->closeBox();
@ -684,8 +684,8 @@ void PeerMenuShareContactBox(
[peer, user] { [peer, user] {
const auto history = peer->owner().history(peer); const auto history = peer->owner().history(peer);
Ui::showPeerHistory(history, ShowAtTheEndMsgId); Ui::showPeerHistory(history, ShowAtTheEndMsgId);
auto options = ApiWrap::SendOptions(history); auto action = Api::SendAction(history);
user->session().api().shareContact(user, options); user->session().api().shareContact(user, action);
}), LayerOption::KeepOther); }), LayerOption::KeepOther);
}; };
*weak = Ui::show(Box<PeerListBox>( *weak = Ui::show(Box<PeerListBox>(
@ -707,15 +707,15 @@ void PeerMenuCreatePoll(not_null<PeerData*> peer) {
if (std::exchange(*lock, true)) { if (std::exchange(*lock, true)) {
return; return;
} }
auto options = ApiWrap::SendOptions(peer->owner().history(peer)); auto action = Api::SendAction(peer->owner().history(peer));
if (const auto id = App::main()->currentReplyToIdFor(options.history)) { if (const auto id = App::main()->currentReplyToIdFor(action.history)) {
options.replyTo = id; action.replyTo = id;
} }
if (const auto localDraft = options.history->localDraft()) { if (const auto localDraft = action.history->localDraft()) {
options.clearDraft = localDraft->textWithTags.text.isEmpty(); action.clearDraft = localDraft->textWithTags.text.isEmpty();
} }
const auto api = &peer->session().api(); const auto api = &peer->session().api();
api->createPoll(result, options, crl::guard(box, [=] { api->createPoll(result, action, crl::guard(box, [=] {
box->closeBox(); box->closeBox();
}), crl::guard(box, [=](const RPCError &error) { }), crl::guard(box, [=](const RPCError &error) {
*lock = false; *lock = false;
@ -822,9 +822,9 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
auto items = peer->owner().idsToItems(ids); auto items = peer->owner().idsToItems(ids);
if (!items.empty()) { if (!items.empty()) {
const auto api = &peer->session().api(); const auto api = &peer->session().api();
auto options = ApiWrap::SendOptions(peer->owner().history(peer)); auto action = Api::SendAction(peer->owner().history(peer));
options.generateLocal = false; action.generateLocal = false;
api->forwardMessages(std::move(items), options, [] { api->forwardMessages(std::move(items), action, [] {
Ui::Toast::Show(tr::lng_share_done(tr::now)); Ui::Toast::Show(tr::lng_share_done(tr::now));
}); });
} }

View File

@ -1,3 +1,4 @@
<(src_loc)/api/api_common.h
<(src_loc)/api/api_hash.h <(src_loc)/api/api_hash.h
<(src_loc)/api/api_sending.cpp <(src_loc)/api/api_sending.cpp
<(src_loc)/api/api_sending.h <(src_loc)/api/api_sending.h