mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-08-30 06:07:45 +00:00
parent
d2b630bbca
commit
0eeeb18ecd
@ -2620,4 +2620,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"ktg_settings_forward_chat_on_click" = "Open chat on click";
|
||||
"ktg_settings_forward_chat_on_click_description" = "You can hold Ctrl to select multiple chats regardless of this option.";
|
||||
|
||||
"ktg_forward_menu_quoted" = "Quoted";
|
||||
"ktg_forward_menu_unquoted" = "Unquoted with captions";
|
||||
"ktg_forward_menu_uncaptioned" = "Unquoted without captions";
|
||||
|
||||
"ktg_forward_menu_default_albums" = "Preserve albums";
|
||||
"ktg_forward_menu_group_all_media" = "Group all media";
|
||||
"ktg_forward_menu_separate_messages" = "Separate messages";
|
||||
|
||||
"ktg_forward_subtitle_unquoted" = "unquoted";
|
||||
"ktg_forward_subtitle_uncaptioned" = "uncaptioned";
|
||||
|
||||
"ktg_forward_subtitle_group_all_media" = "as albums";
|
||||
"ktg_forward_subtitle_separate_messages" = "one by one";
|
||||
|
||||
// Keys finished
|
||||
|
@ -173,6 +173,16 @@
|
||||
"ktg_settings_forward_chat_on_click_description": "You can hold Ctrl to select multiple chats regardless of this option.",
|
||||
|
||||
// New strings
|
||||
"ktg_forward_menu_quoted": "Quoted",
|
||||
"ktg_forward_menu_unquoted": "Unquoted with captions",
|
||||
"ktg_forward_menu_uncaptioned": "Unquoted without captions",
|
||||
"ktg_forward_menu_default_albums": "Preserve albums",
|
||||
"ktg_forward_menu_group_all_media": "Group all media",
|
||||
"ktg_forward_menu_separate_messages": "Separate messages",
|
||||
"ktg_forward_subtitle_unquoted": "unquoted",
|
||||
"ktg_forward_subtitle_uncaptioned": "uncaptioned",
|
||||
"ktg_forward_subtitle_group_all_media": "as albums",
|
||||
"ktg_forward_subtitle_separate_messages": "one by one",
|
||||
|
||||
// This string should always be last for better work with Git.
|
||||
"dummy_last_string": ""
|
||||
|
@ -173,6 +173,16 @@
|
||||
"ktg_settings_forward_chat_on_click_description": "Puoi tenere premuto Ctrl per selezionare più chat insieme indipendentemente da questa opzione.",
|
||||
|
||||
// New strings
|
||||
"ktg_forward_menu_quoted": "Quoted",
|
||||
"ktg_forward_menu_unquoted": "Unquoted with captions",
|
||||
"ktg_forward_menu_uncaptioned": "Unquoted without captions",
|
||||
"ktg_forward_menu_default_albums": "Preserve albums",
|
||||
"ktg_forward_menu_group_all_media": "Group all media",
|
||||
"ktg_forward_menu_separate_messages": "Separate messages",
|
||||
"ktg_forward_subtitle_unquoted": "unquoted",
|
||||
"ktg_forward_subtitle_uncaptioned": "uncaptioned",
|
||||
"ktg_forward_subtitle_group_all_media": "as albums",
|
||||
"ktg_forward_subtitle_separate_messages": "one by one",
|
||||
|
||||
// This string should always be last for better work with Git.
|
||||
"dummy_last_string": ""
|
||||
|
@ -181,6 +181,16 @@
|
||||
"ktg_settings_forward_chat_on_click_description": "You can hold Ctrl to select multiple chats regardless of this option.",
|
||||
|
||||
// New strings
|
||||
"ktg_forward_menu_quoted": "Quoted",
|
||||
"ktg_forward_menu_unquoted": "Unquoted with captions",
|
||||
"ktg_forward_menu_uncaptioned": "Unquoted without captions",
|
||||
"ktg_forward_menu_default_albums": "Preserve albums",
|
||||
"ktg_forward_menu_group_all_media": "Group all media",
|
||||
"ktg_forward_menu_separate_messages": "Separate messages",
|
||||
"ktg_forward_subtitle_unquoted": "unquoted",
|
||||
"ktg_forward_subtitle_uncaptioned": "uncaptioned",
|
||||
"ktg_forward_subtitle_group_all_media": "as albums",
|
||||
"ktg_forward_subtitle_separate_messages": "one by one",
|
||||
|
||||
// This string should always be last for better work with Git.
|
||||
"dummy_last_string": ""
|
||||
|
@ -173,6 +173,16 @@
|
||||
"ktg_settings_forward_chat_on_click_description": "Você pode pressionar Ctrl para selecionar vários chats, independentemente desta opção.",
|
||||
|
||||
// New strings
|
||||
"ktg_forward_menu_quoted": "Quoted",
|
||||
"ktg_forward_menu_unquoted": "Unquoted with captions",
|
||||
"ktg_forward_menu_uncaptioned": "Unquoted without captions",
|
||||
"ktg_forward_menu_default_albums": "Preserve albums",
|
||||
"ktg_forward_menu_group_all_media": "Group all media",
|
||||
"ktg_forward_menu_separate_messages": "Separate messages",
|
||||
"ktg_forward_subtitle_unquoted": "unquoted",
|
||||
"ktg_forward_subtitle_uncaptioned": "uncaptioned",
|
||||
"ktg_forward_subtitle_group_all_media": "as albums",
|
||||
"ktg_forward_subtitle_separate_messages": "one by one",
|
||||
|
||||
// This string should always be last for better work with Git.
|
||||
"dummy_last_string": ""
|
||||
|
@ -180,6 +180,16 @@
|
||||
"ktg_settings_forward_chat_on_click_description": "Удерживайте Ctrl для выбора нескольких чатов вне зависимости от этой настройки.",
|
||||
|
||||
// New strings
|
||||
"ktg_forward_menu_quoted": "С автором",
|
||||
"ktg_forward_menu_unquoted": "Без автора с подписями",
|
||||
"ktg_forward_menu_uncaptioned": "Без автора и подписей",
|
||||
"ktg_forward_menu_default_albums": "Оригинальные альбомы",
|
||||
"ktg_forward_menu_group_all_media": "Объединить все медиа",
|
||||
"ktg_forward_menu_separate_messages": "Отдельные сообщения",
|
||||
"ktg_forward_subtitle_unquoted": "без автора",
|
||||
"ktg_forward_subtitle_uncaptioned": "без подписей",
|
||||
"ktg_forward_subtitle_group_all_media": "альбомами",
|
||||
"ktg_forward_subtitle_separate_messages": "по одному",
|
||||
|
||||
// This string should always be last for better work with Git.
|
||||
"dummy_last_string": ""
|
||||
|
@ -173,6 +173,16 @@
|
||||
"ktg_settings_forward_chat_on_click_description": "Ctrl tuşunu uzun tutarak birden fazla sohbet seçmek için, bu seçenek aktifligine rağmen.",
|
||||
|
||||
// New strings
|
||||
"ktg_forward_menu_quoted": "Quoted",
|
||||
"ktg_forward_menu_unquoted": "Unquoted with captions",
|
||||
"ktg_forward_menu_uncaptioned": "Unquoted without captions",
|
||||
"ktg_forward_menu_default_albums": "Preserve albums",
|
||||
"ktg_forward_menu_group_all_media": "Group all media",
|
||||
"ktg_forward_menu_separate_messages": "Separate messages",
|
||||
"ktg_forward_subtitle_unquoted": "unquoted",
|
||||
"ktg_forward_subtitle_uncaptioned": "uncaptioned",
|
||||
"ktg_forward_subtitle_group_all_media": "as albums",
|
||||
"ktg_forward_subtitle_separate_messages": "one by one",
|
||||
|
||||
// This string should always be last for better work with Git.
|
||||
"dummy_last_string": ""
|
||||
|
@ -180,6 +180,16 @@
|
||||
"ktg_settings_forward_chat_on_click_description": "Ви можете вибрати декілька чатів утримуючи Ctrl незалежно від цього параметра.",
|
||||
|
||||
// New strings
|
||||
"ktg_forward_menu_quoted": "Quoted",
|
||||
"ktg_forward_menu_unquoted": "Unquoted with captions",
|
||||
"ktg_forward_menu_uncaptioned": "Unquoted without captions",
|
||||
"ktg_forward_menu_default_albums": "Preserve albums",
|
||||
"ktg_forward_menu_group_all_media": "Group all media",
|
||||
"ktg_forward_menu_separate_messages": "Separate messages",
|
||||
"ktg_forward_subtitle_unquoted": "unquoted",
|
||||
"ktg_forward_subtitle_uncaptioned": "uncaptioned",
|
||||
"ktg_forward_subtitle_group_all_media": "as albums",
|
||||
"ktg_forward_subtitle_separate_messages": "one by one",
|
||||
|
||||
// This string should always be last for better work with Git.
|
||||
"dummy_last_string": ""
|
||||
|
@ -3890,7 +3890,7 @@ void ApiWrap::forwardMessages(
|
||||
}
|
||||
|
||||
const auto count = int(items.size());
|
||||
const auto genClientSideMessage = action.generateLocal && (count < 2);
|
||||
const auto genClientSideMessage = action.generateLocal && (count < 2) && cForwardQuoted();
|
||||
const auto history = action.history;
|
||||
const auto peer = history->peer;
|
||||
|
||||
@ -3916,18 +3916,47 @@ void ApiWrap::forwardMessages(
|
||||
|
||||
auto forwardFrom = items.front()->history()->peer;
|
||||
auto currentGroupId = items.front()->groupId();
|
||||
auto isLastGrouped = false;
|
||||
auto ids = QVector<MTPint>();
|
||||
auto randomIds = QVector<MTPlong>();
|
||||
auto localIds = std::shared_ptr<base::flat_map<uint64, FullMsgId>>();
|
||||
auto fromIter = items.begin();
|
||||
auto toIter = items.begin();
|
||||
|
||||
const auto sendAccumulated = [&] {
|
||||
const auto needNextGroup = [&] (not_null<HistoryItem *> item) {
|
||||
if (cForwardAlbumsAsIs()) {
|
||||
const auto newFrom = item->history()->peer;
|
||||
const auto newGroupId = item->groupId();
|
||||
return forwardFrom != newFrom
|
||||
|| currentGroupId != newGroupId;
|
||||
} else if (cForwardGrouped()) {
|
||||
if (item->media() && item->media()->canBeGrouped()) {
|
||||
return !isLastGrouped;
|
||||
} else {
|
||||
return isLastGrouped;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const auto isGrouped = [&] {
|
||||
return (cForwardAlbumsAsIs()
|
||||
&& currentGroupId != MessageGroupId())
|
||||
|| (!cForwardAlbumsAsIs()
|
||||
&& cForwardGrouped()
|
||||
&& items.front()->media()
|
||||
&& items.front()->media()->canBeGrouped());
|
||||
};
|
||||
|
||||
const auto forwardQuoted = [&] {
|
||||
if (shared) {
|
||||
++shared->requestsLeft;
|
||||
}
|
||||
const auto finalFlags = sendFlags
|
||||
| (currentGroupId == MessageGroupId()
|
||||
? MTPmessages_ForwardMessages::Flag(0)
|
||||
: MTPmessages_ForwardMessages::Flag::f_grouped);
|
||||
| (isGrouped()
|
||||
? MTPmessages_ForwardMessages::Flag::f_grouped
|
||||
: MTPmessages_ForwardMessages::Flag(0));
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_ForwardMessages(
|
||||
@ -3957,6 +3986,308 @@ void ApiWrap::forwardMessages(
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
};
|
||||
|
||||
const auto forwardQuotedSingle = [&] (not_null<HistoryItem *> item) {
|
||||
if (shared) {
|
||||
++shared->requestsLeft;
|
||||
}
|
||||
|
||||
auto currentIds = QVector<MTPint>();
|
||||
currentIds.push_back(MTP_int(item->id));
|
||||
|
||||
auto currentRandomId = randomIds.takeFirst();
|
||||
auto currentRandomIds = QVector<MTPlong>();
|
||||
currentRandomIds.push_back(currentRandomId);
|
||||
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_ForwardMessages(
|
||||
MTP_flags(sendFlags),
|
||||
forwardFrom->input,
|
||||
MTP_vector<MTPint>(currentIds),
|
||||
MTP_vector<MTPlong>(currentRandomIds),
|
||||
peer->input,
|
||||
MTP_int(action.options.scheduled)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
if (shared && !--shared->requestsLeft) {
|
||||
shared->callback();
|
||||
}
|
||||
finish();
|
||||
}).fail([=, ids = localIds](const RPCError &error) {
|
||||
auto found = false;
|
||||
for (const auto &[randomId, itemId] : *ids) {
|
||||
if (currentRandomId == MTP_long(randomId)) {
|
||||
sendMessageFail(error, peer, randomId, itemId);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
sendMessageFail(error, peer);
|
||||
}
|
||||
finish();
|
||||
}).afterRequest(
|
||||
history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
};
|
||||
|
||||
const auto forwardAlbumUnquoted = [&] {
|
||||
if (shared) {
|
||||
++shared->requestsLeft;
|
||||
}
|
||||
auto medias = QVector<MTPInputSingleMedia>();
|
||||
medias.reserve(ids.size());
|
||||
|
||||
for (auto i = fromIter, e = toIter; i != e; i++) {
|
||||
const auto item = *i;
|
||||
const auto media = item->media();
|
||||
auto inputMedia = media->photo()
|
||||
? MTP_inputMediaPhoto(MTP_flags(0), media->photo()->mtpInput(), MTPint())
|
||||
: MTP_inputMediaDocument(MTP_flags(0), media->document()->mtpInput(), MTPint());
|
||||
auto caption = cForwardCaptioned()
|
||||
? item->originalText()
|
||||
: TextWithEntities();
|
||||
auto sentEntities = Api::EntitiesToMTP(
|
||||
_session,
|
||||
caption.entities,
|
||||
Api::ConvertOption::SkipLocal);
|
||||
|
||||
const auto flags = !sentEntities.v.isEmpty()
|
||||
? MTPDinputSingleMedia::Flag::f_entities
|
||||
: MTPDinputSingleMedia::Flag(0);
|
||||
|
||||
auto randomId = randomIds.takeFirst();
|
||||
|
||||
medias.push_back(MTP_inputSingleMedia(
|
||||
MTP_flags(flags),
|
||||
inputMedia,
|
||||
randomId,
|
||||
MTP_string(caption.text),
|
||||
sentEntities));
|
||||
}
|
||||
|
||||
const auto finalFlags = MTPmessages_SendMultiMedia::Flags(0)
|
||||
| (action.options.silent
|
||||
? MTPmessages_SendMultiMedia::Flag::f_silent
|
||||
: MTPmessages_SendMultiMedia::Flag(0))
|
||||
| (action.options.scheduled
|
||||
? MTPmessages_SendMultiMedia::Flag::f_schedule_date
|
||||
: MTPmessages_SendMultiMedia::Flag(0));
|
||||
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_SendMultiMedia(
|
||||
MTP_flags(finalFlags),
|
||||
peer->input,
|
||||
MTPint(),
|
||||
MTP_vector<MTPInputSingleMedia>(medias),
|
||||
MTP_int(action.options.scheduled)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
if (shared && !--shared->requestsLeft) {
|
||||
shared->callback();
|
||||
}
|
||||
finish();
|
||||
}).fail([=, ids = localIds](const RPCError &error) {
|
||||
if (ids) {
|
||||
for (const auto &[randomId, itemId] : *ids) {
|
||||
sendMessageFail(error, peer, randomId, itemId);
|
||||
}
|
||||
} else {
|
||||
sendMessageFail(error, peer);
|
||||
}
|
||||
finish();
|
||||
}).afterRequest(
|
||||
history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
};
|
||||
|
||||
const auto forwardMediaUnquoted = [&] (not_null<HistoryItem *> item) {
|
||||
if (shared) {
|
||||
++shared->requestsLeft;
|
||||
}
|
||||
const auto media = item->media();
|
||||
|
||||
auto newSendFlags = MTPmessages_SendMedia::Flags(0)
|
||||
| (action.options.silent
|
||||
? MTPmessages_SendMedia::Flag::f_silent
|
||||
: MTPmessages_SendMedia::Flag(0))
|
||||
| (action.options.scheduled
|
||||
? MTPmessages_SendMedia::Flag::f_schedule_date
|
||||
: MTPmessages_SendMedia::Flag(0));
|
||||
|
||||
auto caption = (cForwardCaptioned()
|
||||
&& !media->geoPoint()
|
||||
&& !media->sharedContact())
|
||||
? item->originalText()
|
||||
: TextWithEntities();
|
||||
|
||||
auto sentEntities = Api::EntitiesToMTP(
|
||||
_session,
|
||||
caption.entities,
|
||||
Api::ConvertOption::SkipLocal);
|
||||
if (!sentEntities.v.isEmpty()) {
|
||||
newSendFlags |= MTPmessages_SendMedia::Flag::f_entities;
|
||||
}
|
||||
|
||||
auto inputMedia = media->poll()
|
||||
? PollDataToInputMedia(media->poll())
|
||||
: media->geoPoint()
|
||||
? MTP_inputMediaGeoPoint(
|
||||
MTP_inputGeoPoint(
|
||||
MTP_double(media->geoPoint()->lat()),
|
||||
MTP_double(media->geoPoint()->lon())))
|
||||
: media->sharedContact()
|
||||
? MTP_inputMediaContact(
|
||||
MTP_string(media->sharedContact()->phoneNumber),
|
||||
MTP_string(media->sharedContact()->firstName),
|
||||
MTP_string(media->sharedContact()->lastName),
|
||||
MTPstring())
|
||||
: media->photo()
|
||||
? MTP_inputMediaPhoto(MTP_flags(0), media->photo()->mtpInput(), MTPint())
|
||||
: MTP_inputMediaDocument(MTP_flags(0), media->document()->mtpInput(), MTPint());
|
||||
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
const auto currentRandomId = randomIds.takeFirst();
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_SendMedia(
|
||||
MTP_flags(newSendFlags),
|
||||
peer->input,
|
||||
MTPint(),
|
||||
inputMedia,
|
||||
MTP_string(caption.text),
|
||||
currentRandomId,
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(action.options.scheduled)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
if (shared && !--shared->requestsLeft) {
|
||||
shared->callback();
|
||||
}
|
||||
finish();
|
||||
}).fail([=, ids = localIds](const RPCError &error) {
|
||||
if (ids) {
|
||||
auto found = false;
|
||||
for (const auto &[randomId, itemId] : *ids) {
|
||||
if (currentRandomId == MTP_long(randomId)) {
|
||||
sendMessageFail(error, peer, randomId, itemId);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
sendMessageFail(error, peer);
|
||||
}
|
||||
} else {
|
||||
sendMessageFail(error, peer);
|
||||
}
|
||||
finish();
|
||||
}).afterRequest(
|
||||
history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
};
|
||||
|
||||
const auto forwardMessageUnquoted = [&] (not_null<HistoryItem *> item) {
|
||||
if (shared) {
|
||||
++shared->requestsLeft;
|
||||
}
|
||||
const auto media = item->media();
|
||||
|
||||
auto newSendFlags = MTPmessages_SendMessage::Flag(0)
|
||||
| (!media || !media->webpage()
|
||||
? MTPmessages_SendMessage::Flag::f_no_webpage
|
||||
: MTPmessages_SendMessage::Flag(0))
|
||||
| (action.options.silent
|
||||
? MTPmessages_SendMessage::Flag::f_silent
|
||||
: MTPmessages_SendMessage::Flag(0))
|
||||
| (action.options.scheduled
|
||||
? MTPmessages_SendMessage::Flag::f_schedule_date
|
||||
: MTPmessages_SendMessage::Flag(0));
|
||||
|
||||
auto sentEntities = Api::EntitiesToMTP(
|
||||
_session,
|
||||
item->originalText().entities,
|
||||
Api::ConvertOption::SkipLocal);
|
||||
if (!sentEntities.v.isEmpty()) {
|
||||
newSendFlags |= MTPmessages_SendMessage::Flag::f_entities;
|
||||
}
|
||||
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
const auto currentRandomId = randomIds.takeFirst();
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_SendMessage(
|
||||
MTP_flags(newSendFlags),
|
||||
peer->input,
|
||||
MTPint(),
|
||||
MTP_string(item->originalText().text),
|
||||
currentRandomId,
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(action.options.scheduled)
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
if (shared && !--shared->requestsLeft) {
|
||||
shared->callback();
|
||||
}
|
||||
finish();
|
||||
}).fail([=, ids = localIds](const RPCError &error) {
|
||||
if (ids) {
|
||||
auto found = false;
|
||||
for (const auto &[randomId, itemId] : *ids) {
|
||||
if (currentRandomId == MTP_long(randomId)) {
|
||||
sendMessageFail(error, peer, randomId, itemId);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
sendMessageFail(error, peer);
|
||||
}
|
||||
} else {
|
||||
sendMessageFail(error, peer);
|
||||
}
|
||||
finish();
|
||||
}).afterRequest(
|
||||
history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
};
|
||||
|
||||
const auto sendAccumulated = [&] {
|
||||
if (cForwardQuoted()) {
|
||||
forwardQuoted();
|
||||
} else if (isGrouped()) {
|
||||
forwardAlbumUnquoted();
|
||||
} else {
|
||||
for (auto i = fromIter, e = toIter; i != e; i++) {
|
||||
const auto item = *i;
|
||||
const auto media = item->media();
|
||||
|
||||
if (media && !media->webpage()) {
|
||||
if (media->poll()
|
||||
|| media->geoPoint()
|
||||
|| media->sharedContact()
|
||||
|| media->photo()
|
||||
|| media->document()) {
|
||||
forwardMediaUnquoted(item);
|
||||
} else {
|
||||
forwardQuotedSingle(item);
|
||||
}
|
||||
} else {
|
||||
forwardMessageUnquoted(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ids.resize(0);
|
||||
randomIds.resize(0);
|
||||
@ -3965,7 +4296,8 @@ void ApiWrap::forwardMessages(
|
||||
|
||||
ids.reserve(count);
|
||||
randomIds.reserve(count);
|
||||
for (const auto item : items) {
|
||||
for (auto i = items.begin(), e = items.end(); i != e; /* ++i is in the end */) {
|
||||
const auto item = *i;
|
||||
const auto randomId = rand_value<uint64>();
|
||||
if (genClientSideMessage) {
|
||||
if (const auto message = item->toHistoryMessage()) {
|
||||
@ -3994,16 +4326,18 @@ void ApiWrap::forwardMessages(
|
||||
localIds->emplace(randomId, newId);
|
||||
}
|
||||
}
|
||||
const auto newFrom = item->history()->peer;
|
||||
const auto newGroupId = item->groupId();
|
||||
if (forwardFrom != newFrom
|
||||
|| currentGroupId != newGroupId) {
|
||||
if (needNextGroup(item)) {
|
||||
sendAccumulated();
|
||||
forwardFrom = newFrom;
|
||||
currentGroupId = newGroupId;
|
||||
forwardFrom = item->history()->peer;
|
||||
currentGroupId = item->groupId();
|
||||
fromIter = i;
|
||||
}
|
||||
ids.push_back(MTP_int(item->id));
|
||||
randomIds.push_back(MTP_long(randomId));
|
||||
if (item->media() && item->media()->canBeGrouped()) {
|
||||
isLastGrouped = true;
|
||||
}
|
||||
toIter = ++i;
|
||||
}
|
||||
sendAccumulated();
|
||||
_session->data().sendHistoryChangeNotifications();
|
||||
|
@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
@ -41,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_layers.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_history.h"
|
||||
#include "styles/style_info.h"
|
||||
|
||||
class ShareBox::Inner final : public Ui::RpWidget, private base::Subscriber {
|
||||
public:
|
||||
@ -166,13 +168,15 @@ ShareBox::ShareBox(
|
||||
CopyCallback &©Callback,
|
||||
SubmitCallback &&submitCallback,
|
||||
FilterCallback &&filterCallback,
|
||||
GoToChatCallback &&goToChatCallback)
|
||||
GoToChatCallback &&goToChatCallback,
|
||||
bool hasMedia)
|
||||
: _navigation(navigation)
|
||||
, _api(&_navigation->session().mtp())
|
||||
, _copyCallback(std::move(copyCallback))
|
||||
, _submitCallback(std::move(submitCallback))
|
||||
, _filterCallback(std::move(filterCallback))
|
||||
, _goToChatCallback(goToChatCallback ? std::move(goToChatCallback) : nullptr)
|
||||
, _hasMediaMessages(hasMedia)
|
||||
, _select(
|
||||
this,
|
||||
st::contactsMultiSelect,
|
||||
@ -226,6 +230,7 @@ void ShareBox::prepare() {
|
||||
Ui::SendPendingMoveResizeEvents(_select);
|
||||
|
||||
setTitle(tr::lng_selected_forward());
|
||||
updateAdditionalTitle();
|
||||
|
||||
_inner = setInnerWidget(
|
||||
object_ptr<Inner>(
|
||||
@ -447,6 +452,9 @@ SendMenu::Type ShareBox::sendMenuType() const {
|
||||
|
||||
void ShareBox::createButtons() {
|
||||
clearButtons();
|
||||
const auto moreButton = addTopButton(st::infoTopBarMenu);
|
||||
moreButton->setClickedCallback([=] { showMenu(moreButton.data()); });
|
||||
|
||||
if (_hasSelected) {
|
||||
if (_goToChatCallback && _inner->selected().size() == 1) {
|
||||
const auto singleChat = _inner->selected().at(0);
|
||||
@ -467,6 +475,109 @@ void ShareBox::createButtons() {
|
||||
addButton(tr::lng_cancel(), [=] { closeBox(); });
|
||||
}
|
||||
|
||||
bool ShareBox::showMenu(not_null<Ui::IconButton*> button) {
|
||||
if (_menu) {
|
||||
_menu->hideAnimated(Ui::InnerDropdown::HideOption::IgnoreShow);
|
||||
return true;
|
||||
}
|
||||
|
||||
_menu = base::make_unique_q<Ui::DropdownMenu>(window());
|
||||
const auto weak = _menu.get();
|
||||
_menu->setHiddenCallback([=] {
|
||||
weak->deleteLater();
|
||||
if (_menu == weak) {
|
||||
button->setForceRippled(false);
|
||||
}
|
||||
});
|
||||
_menu->setShowStartCallback([=] {
|
||||
if (_menu == weak) {
|
||||
button->setForceRippled(true);
|
||||
}
|
||||
});
|
||||
_menu->setHideStartCallback([=] {
|
||||
if (_menu == weak) {
|
||||
button->setForceRippled(false);
|
||||
}
|
||||
});
|
||||
button->installEventFilter(_menu);
|
||||
|
||||
if (!cForwardQuoted()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_quoted(tr::now), [=] {
|
||||
cSetForwardQuoted(true);
|
||||
updateAdditionalTitle();
|
||||
});
|
||||
}
|
||||
if (cForwardQuoted() || !cForwardCaptioned()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_unquoted(tr::now), [=] {
|
||||
cSetForwardQuoted(false);
|
||||
cSetForwardCaptioned(true);
|
||||
updateAdditionalTitle();
|
||||
});
|
||||
}
|
||||
if (cForwardQuoted() || cForwardCaptioned()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_uncaptioned(tr::now), [=] {
|
||||
cSetForwardQuoted(false);
|
||||
cSetForwardCaptioned(false);
|
||||
updateAdditionalTitle();
|
||||
});
|
||||
}
|
||||
if (_hasMediaMessages) {
|
||||
_menu->addSeparator();
|
||||
if (!cForwardAlbumsAsIs()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_default_albums(tr::now), [=] {
|
||||
cSetForwardAlbumsAsIs(true);
|
||||
updateAdditionalTitle();
|
||||
});
|
||||
}
|
||||
if (cForwardAlbumsAsIs() || !cForwardGrouped()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_group_all_media(tr::now), [=] {
|
||||
cSetForwardAlbumsAsIs(false);
|
||||
cSetForwardGrouped(true);
|
||||
updateAdditionalTitle();
|
||||
});
|
||||
}
|
||||
if (cForwardAlbumsAsIs() || cForwardGrouped()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_separate_messages(tr::now), [=] {
|
||||
cSetForwardAlbumsAsIs(false);
|
||||
cSetForwardGrouped(false);
|
||||
updateAdditionalTitle();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const auto parentTopLeft = window()->mapToGlobal({ 0, 0 });
|
||||
const auto buttonTopLeft = button->mapToGlobal({ 0, 0 });
|
||||
const auto parentRect = QRect(parentTopLeft, window()->size());
|
||||
const auto buttonRect = QRect(buttonTopLeft, button->size());
|
||||
_menu->move(
|
||||
buttonRect.x() + buttonRect.width() - _menu->width() - parentRect.x(),
|
||||
buttonRect.y() + buttonRect.height() - parentRect.y() - style::ConvertScale(18));
|
||||
_menu->showAnimated(Ui::PanelAnimation::Origin::TopRight);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShareBox::updateAdditionalTitle() {
|
||||
QString result;
|
||||
|
||||
if (!cForwardQuoted()) {
|
||||
result += (cForwardCaptioned()
|
||||
? tr::ktg_forward_subtitle_unquoted(tr::now)
|
||||
: tr::ktg_forward_subtitle_uncaptioned(tr::now));
|
||||
}
|
||||
|
||||
if (_hasMediaMessages && !cForwardAlbumsAsIs()) {
|
||||
if (!result.isEmpty()) {
|
||||
result += ", ";
|
||||
}
|
||||
result += (cForwardGrouped()
|
||||
? tr::ktg_forward_subtitle_group_all_media(tr::now)
|
||||
: tr::ktg_forward_subtitle_separate_messages(tr::now));
|
||||
}
|
||||
|
||||
setAdditionalTitle(rpl::single(result));
|
||||
}
|
||||
|
||||
void ShareBox::applyFilterUpdate(const QString &query) {
|
||||
onScrollToY(0);
|
||||
_inner->updateFilter(query);
|
||||
|
@ -38,6 +38,7 @@ class IndexedList;
|
||||
namespace Ui {
|
||||
class MultiSelect;
|
||||
class InputField;
|
||||
class DropdownMenu;
|
||||
struct ScrollToRequest;
|
||||
template <typename Widget>
|
||||
class SlideWrap;
|
||||
@ -67,7 +68,8 @@ public:
|
||||
CopyCallback &©Callback,
|
||||
SubmitCallback &&submitCallback,
|
||||
FilterCallback &&filterCallback,
|
||||
GoToChatCallback &&goToChatCallback = nullptr);
|
||||
GoToChatCallback &&goToChatCallback = nullptr,
|
||||
bool hasMedia = false);
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
@ -94,6 +96,8 @@ private:
|
||||
void applyFilterUpdate(const QString &query);
|
||||
void selectedChanged();
|
||||
void createButtons();
|
||||
bool showMenu(not_null<Ui::IconButton*> button);
|
||||
void updateAdditionalTitle();
|
||||
int getTopScrollSkip() const;
|
||||
int getBottomScrollSkip() const;
|
||||
int contentHeight() const;
|
||||
@ -115,6 +119,8 @@ private:
|
||||
FilterCallback _filterCallback;
|
||||
GoToChatCallback _goToChatCallback;
|
||||
|
||||
bool _hasMediaMessages = false;
|
||||
|
||||
object_ptr<Ui::MultiSelect> _select;
|
||||
object_ptr<Ui::SlideWrap<Ui::InputField>> _comment;
|
||||
|
||||
@ -136,4 +142,6 @@ private:
|
||||
|
||||
Ui::Animations::Simple _scrollAnimation;
|
||||
|
||||
base::unique_qptr<Ui::DropdownMenu> _menu;
|
||||
|
||||
};
|
||||
|
@ -182,6 +182,10 @@ PollData *Media::poll() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const LocationPoint *Media::geoPoint() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Media::uploading() const {
|
||||
return false;
|
||||
}
|
||||
@ -808,6 +812,10 @@ Data::CloudImage *MediaLocation::location() const {
|
||||
return _location;
|
||||
}
|
||||
|
||||
const LocationPoint *MediaLocation::geoPoint() const {
|
||||
return &_point;
|
||||
}
|
||||
|
||||
QString MediaLocation::chatListText() const {
|
||||
return WithCaptionDialogsText(tr::lng_maps_point(tr::now), _title);
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ public:
|
||||
virtual const Invoice *invoice() const;
|
||||
virtual Data::CloudImage *location() const;
|
||||
virtual PollData *poll() const;
|
||||
virtual const LocationPoint *geoPoint() const;
|
||||
|
||||
virtual bool uploading() const;
|
||||
virtual Storage::SharedMediaTypesMask sharedMediaTypes() const;
|
||||
@ -245,6 +246,7 @@ public:
|
||||
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
|
||||
|
||||
Data::CloudImage *location() const override;
|
||||
const LocationPoint *geoPoint() const override;
|
||||
QString chatListText() const override;
|
||||
QString notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
|
@ -5172,6 +5172,9 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
||||
updateField();
|
||||
} else if (_inReplyEditForward) {
|
||||
if (readyToForward()) {
|
||||
if (e->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
const auto items = std::move(_toForward);
|
||||
session().data().cancelForwarding(_history);
|
||||
auto list = ranges::view::all(
|
||||
@ -5189,6 +5192,92 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::contextMenuEvent(QContextMenuEvent *e) {
|
||||
if (_menu) {
|
||||
return;
|
||||
}
|
||||
const auto hasSecondLayer = (_editMsgId
|
||||
|| _replyToId
|
||||
|| readyToForward()
|
||||
|| _kbReplyTo);
|
||||
_replyForwardPressed = hasSecondLayer && QRect(
|
||||
0,
|
||||
_field->y() - st::historySendPadding - st::historyReplyHeight,
|
||||
st::historyReplySkip,
|
||||
st::historyReplyHeight).contains(e->pos());
|
||||
if (_replyForwardPressed && !_fieldBarCancel->isHidden()) {
|
||||
return;
|
||||
} else if (_inReplyEditForward) {
|
||||
if (readyToForward()) {
|
||||
const auto count = int(_toForward.size());
|
||||
auto hasMediaToGroup = false;
|
||||
|
||||
if (count > 1) {
|
||||
auto grouppableMediaCount = 0;
|
||||
for (const auto item : _toForward) {
|
||||
if (item->media() && item->media()->canBeGrouped()) {
|
||||
grouppableMediaCount++;
|
||||
} else {
|
||||
grouppableMediaCount = 0;
|
||||
}
|
||||
if (grouppableMediaCount > 1) {
|
||||
hasMediaToGroup = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_menu = base::make_unique_q<Ui::PopupMenu>(this);
|
||||
|
||||
if (!cForwardQuoted()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_quoted(tr::now), [=] {
|
||||
cSetForwardQuoted(true);
|
||||
updateForwardingTexts();
|
||||
});
|
||||
}
|
||||
if (cForwardQuoted() || !cForwardCaptioned()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_unquoted(tr::now), [=] {
|
||||
cSetForwardQuoted(false);
|
||||
cSetForwardCaptioned(true);
|
||||
updateForwardingTexts();
|
||||
});
|
||||
}
|
||||
if (cForwardQuoted() || cForwardCaptioned()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_uncaptioned(tr::now), [=] {
|
||||
cSetForwardQuoted(false);
|
||||
cSetForwardCaptioned(false);
|
||||
updateForwardingTexts();
|
||||
});
|
||||
}
|
||||
if (hasMediaToGroup && count > 1) {
|
||||
_menu->addSeparator();
|
||||
if (!cForwardAlbumsAsIs()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_default_albums(tr::now), [=] {
|
||||
cSetForwardAlbumsAsIs(true);
|
||||
updateForwardingTexts();
|
||||
});
|
||||
}
|
||||
if (cForwardAlbumsAsIs() || !cForwardGrouped()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_group_all_media(tr::now), [=] {
|
||||
cSetForwardAlbumsAsIs(false);
|
||||
cSetForwardGrouped(true);
|
||||
updateForwardingTexts();
|
||||
});
|
||||
}
|
||||
if (cForwardAlbumsAsIs() || cForwardGrouped()) {
|
||||
_menu->addAction(tr::ktg_forward_menu_separate_messages(tr::now), [=] {
|
||||
cSetForwardAlbumsAsIs(false);
|
||||
cSetForwardGrouped(false);
|
||||
updateForwardingTexts();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_menu->popup(QCursor::pos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::keyPressEvent(QKeyEvent *e) {
|
||||
if (!_history) return;
|
||||
|
||||
@ -6319,6 +6408,8 @@ void HistoryWidget::updateForwardingTexts() {
|
||||
auto insertedPeers = base::flat_set<not_null<PeerData*>>();
|
||||
auto insertedNames = base::flat_set<QString>();
|
||||
auto fullname = QString();
|
||||
auto hasMediaToGroup = false;
|
||||
auto grouppableMediaCount = 0;
|
||||
auto names = std::vector<QString>();
|
||||
names.reserve(_toForward.size());
|
||||
for (const auto item : _toForward) {
|
||||
@ -6339,7 +6430,18 @@ void HistoryWidget::updateForwardingTexts() {
|
||||
} else {
|
||||
Unexpected("Corrupt forwarded information in message.");
|
||||
}
|
||||
if (!hasMediaToGroup) {
|
||||
if (item->media() && item->media()->canBeGrouped()) {
|
||||
grouppableMediaCount++;
|
||||
} else {
|
||||
grouppableMediaCount = 0;
|
||||
}
|
||||
if (grouppableMediaCount > 1) {
|
||||
hasMediaToGroup = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (names.size() > 2) {
|
||||
from = tr::lng_forwarding_from(tr::now, lt_count, names.size() - 1, lt_user, names[0]);
|
||||
} else if (names.size() < 2) {
|
||||
@ -6348,10 +6450,20 @@ void HistoryWidget::updateForwardingTexts() {
|
||||
from = tr::lng_forwarding_from_two(tr::now, lt_user, names[0], lt_second_user, names[1]);
|
||||
}
|
||||
|
||||
if (count < 2) {
|
||||
if (count < 2 && cForwardQuoted()) {
|
||||
text = _toForward.front()->inReplyText();
|
||||
} else {
|
||||
text = textcmdLink(1, tr::lng_forward_messages(tr::now, lt_count, count));
|
||||
text = textcmdLink(1, tr::lng_forward_messages(tr::now, lt_count, count)
|
||||
+ (cForwardQuoted()
|
||||
? QString()
|
||||
: qsl(", ") + (cForwardCaptioned()
|
||||
? tr::ktg_forward_subtitle_unquoted(tr::now)
|
||||
: tr::ktg_forward_subtitle_uncaptioned(tr::now)))
|
||||
+ (cForwardAlbumsAsIs() || !hasMediaToGroup
|
||||
? QString()
|
||||
: qsl(", ") + (cForwardGrouped()
|
||||
? tr::ktg_forward_subtitle_group_all_media(tr::now)
|
||||
: tr::ktg_forward_subtitle_separate_messages(tr::now))));
|
||||
}
|
||||
}
|
||||
_toForwardFrom.setText(st::msgNameStyle, from, Ui::NameTextOptions());
|
||||
|
@ -287,6 +287,7 @@ protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
@ -769,4 +770,6 @@ private:
|
||||
|
||||
int _topDelta = 0;
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
|
||||
};
|
||||
|
@ -219,3 +219,8 @@ QString gApiHash;
|
||||
|
||||
bool gUseEnvApi = true;
|
||||
bool gApiFromStartParams = false;
|
||||
|
||||
bool gForwardQuoted = true;
|
||||
bool gForwardCaptioned = true;
|
||||
bool gForwardAlbumsAsIs = true;
|
||||
bool gForwardGrouped = false;
|
||||
|
@ -129,3 +129,8 @@ DeclareSetting(int, ApiId);
|
||||
DeclareSetting(QString, ApiHash);
|
||||
DeclareSetting(bool, UseEnvApi);
|
||||
DeclareSetting(bool, ApiFromStartParams);
|
||||
|
||||
DeclareSetting(bool, ForwardQuoted);
|
||||
DeclareSetting(bool, ForwardCaptioned);
|
||||
DeclareSetting(bool, ForwardAlbumsAsIs);
|
||||
DeclareSetting(bool, ForwardGrouped);
|
||||
|
@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "api/api_chat_filters.h"
|
||||
#include "api/api_text_entities.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
@ -1045,6 +1046,15 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
||||
FnMut<void()> submitCallback;
|
||||
};
|
||||
struct MsgIdsGroup {
|
||||
MsgIdsGroup() = default;
|
||||
MsgIdsGroup(not_null<HistoryItem*> item, MTPint fullId, bool isGrouped = false)
|
||||
: grouped(isGrouped) {
|
||||
add(item, fullId);
|
||||
}
|
||||
void add(not_null<HistoryItem*> item, MTPint fullId) {
|
||||
items.push_back(item);
|
||||
ids.push_back(fullId);
|
||||
}
|
||||
HistoryItemsList items;
|
||||
QVector<MTPint> ids;
|
||||
bool grouped = false;
|
||||
@ -1058,6 +1068,23 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
||||
&& firstItem->media()
|
||||
&& (firstItem->media()->game() != nullptr);
|
||||
const auto canCopyLink = items.size() == 1 && (firstItem->hasDirectLink() || isGame);
|
||||
auto hasMediaForGrouping = false;
|
||||
|
||||
if (items.size() > 1) {
|
||||
auto grouppableMediaCount = 0;
|
||||
for (const auto item : history->owner().idsToItems(items)) {
|
||||
if (item->media() && item->media()->canBeGrouped()) {
|
||||
grouppableMediaCount++;
|
||||
} else {
|
||||
grouppableMediaCount = 0;
|
||||
}
|
||||
if (grouppableMediaCount > 1) {
|
||||
hasMediaForGrouping = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto data = std::make_shared<ShareData>(history->peer, std::move(items), std::move(successCallback));
|
||||
|
||||
auto copyCallback = [=]() {
|
||||
@ -1128,37 +1155,261 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
||||
: MTPmessages_ForwardMessages::Flag(0));
|
||||
const auto groupedSendFlags = sendFlags | MTPmessages_ForwardMessages::Flag::f_grouped;
|
||||
|
||||
// Regroup messages if needed
|
||||
auto groupedMsgIds = QVector<MsgIdsGroup>();
|
||||
for (const auto fullId : data->msgIds) {
|
||||
auto item = navigation->session().data().message(fullId);
|
||||
auto group = owner->groups().find(item);
|
||||
const auto item = navigation->session().data().message(fullId);
|
||||
const auto group = owner->groups().find(item);
|
||||
const auto canBeGrouped = hasMediaForGrouping && item->media() && item->media()->canBeGrouped();
|
||||
|
||||
if (groupedMsgIds.size()) {
|
||||
auto prevItem = groupedMsgIds.back().items.back();
|
||||
auto prevGroup = owner->groups().find(prevItem);
|
||||
if (prevGroup == group) {
|
||||
groupedMsgIds.back().items.push_back(item);
|
||||
groupedMsgIds.back().ids.push_back(MTP_int(fullId.msg));
|
||||
continue;
|
||||
if (groupedMsgIds.size() > 0) {
|
||||
auto lastGroup = &groupedMsgIds.back();
|
||||
|
||||
if (cForwardAlbumsAsIs()) {
|
||||
if (owner->groups().find(lastGroup->items.back()) == group) {
|
||||
lastGroup->add(item, MTP_int(fullId.msg));
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (lastGroup->grouped) {
|
||||
if (lastGroup->items.size() < 10 && canBeGrouped) {
|
||||
lastGroup->add(item, MTP_int(fullId.msg));
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (!canBeGrouped) {
|
||||
lastGroup->add(item, MTP_int(fullId.msg));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MsgIdsGroup msgIdGroupInst;
|
||||
msgIdGroupInst.items.push_back(item);
|
||||
msgIdGroupInst.ids.push_back(MTP_int(fullId.msg));
|
||||
msgIdGroupInst.grouped = (group != nullptr);
|
||||
groupedMsgIds.push_back(msgIdGroupInst);
|
||||
groupedMsgIds.push_back(MsgIdsGroup(
|
||||
item,
|
||||
MTP_int(fullId.msg),
|
||||
cForwardAlbumsAsIs()
|
||||
? (group != nullptr)
|
||||
: canBeGrouped
|
||||
? cForwardGrouped()
|
||||
: false));
|
||||
}
|
||||
auto generateRandom = [&] (int size) {
|
||||
|
||||
const auto generateRandom = [&] (int size) {
|
||||
auto result = QVector<MTPlong>(size);
|
||||
for (auto &value : result) {
|
||||
value = rand_value<MTPlong>();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const auto checkAndClose = [=] (mtpRequestId requestId) {
|
||||
data->requests.remove(requestId);
|
||||
if (data->requests.empty()) {
|
||||
Ui::Toast::Show(tr::lng_share_done(tr::now));
|
||||
Ui::hideLayer();
|
||||
}
|
||||
};
|
||||
auto &api = owner->session().api();
|
||||
auto &histories = owner->histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
|
||||
const auto forwardQuoted = [&] (
|
||||
MsgIdsGroup &&group,
|
||||
not_null<History*> history,
|
||||
MTPmessages_ForwardMessages::Flags flags) {
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
auto &api = history->session().api();
|
||||
history->sendRequestId = api.request(MTPmessages_ForwardMessages(
|
||||
MTP_flags(flags),
|
||||
data->peer->input,
|
||||
MTP_vector<MTPint>(group.ids),
|
||||
MTP_vector<MTPlong>(generateRandom(group.ids.size())),
|
||||
history->peer->input,
|
||||
MTP_int(options.scheduled)
|
||||
)).done([=](const MTPUpdates &updates, mtpRequestId requestId) {
|
||||
history->session().api().applyUpdates(updates);
|
||||
checkAndClose(requestId);
|
||||
finish();
|
||||
}).fail([=](const RPCError &error) {
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
data->requests.insert(history->sendRequestId);
|
||||
};
|
||||
|
||||
const auto forwardAlbumUnquoted = [&] (MsgIdsGroup &&group, not_null<History*> history) {
|
||||
auto medias = QVector<MTPInputSingleMedia>();
|
||||
medias.reserve(group.items.size());
|
||||
|
||||
auto randomIds = generateRandom(group.items.size());
|
||||
|
||||
for (const auto item : group.items) {
|
||||
const auto media = item->media();
|
||||
const auto inputMedia = media->photo()
|
||||
? MTP_inputMediaPhoto(MTP_flags(0), media->photo()->mtpInput(), MTPint())
|
||||
: MTP_inputMediaDocument(MTP_flags(0), media->document()->mtpInput(), MTPint());
|
||||
const auto caption = cForwardCaptioned()
|
||||
? item->originalText()
|
||||
: TextWithEntities();
|
||||
const auto sentEntities = Api::EntitiesToMTP(
|
||||
session,
|
||||
caption.entities,
|
||||
Api::ConvertOption::SkipLocal);
|
||||
|
||||
const auto flags = !sentEntities.v.isEmpty()
|
||||
? MTPDinputSingleMedia::Flag::f_entities
|
||||
: MTPDinputSingleMedia::Flag(0);
|
||||
|
||||
const auto randomId = randomIds.takeFirst();
|
||||
|
||||
medias.push_back(MTP_inputSingleMedia(
|
||||
MTP_flags(flags),
|
||||
inputMedia,
|
||||
randomId,
|
||||
MTP_string(caption.text),
|
||||
sentEntities));
|
||||
}
|
||||
|
||||
const auto flags = MTPmessages_SendMultiMedia::Flags(0)
|
||||
| (options.silent
|
||||
? MTPmessages_SendMultiMedia::Flag::f_silent
|
||||
: MTPmessages_SendMultiMedia::Flag(0))
|
||||
| (options.scheduled
|
||||
? MTPmessages_SendMultiMedia::Flag::f_schedule_date
|
||||
: MTPmessages_SendMultiMedia::Flag(0));
|
||||
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
auto &api = history->session().api();
|
||||
history->sendRequestId = api.request(MTPmessages_SendMultiMedia(
|
||||
MTP_flags(flags),
|
||||
history->peer->input,
|
||||
MTPint(),
|
||||
MTP_vector<MTPInputSingleMedia>(medias),
|
||||
MTP_int(options.scheduled)
|
||||
)).done([=](const MTPUpdates &updates, mtpRequestId requestId) {
|
||||
history->session().api().applyUpdates(updates);
|
||||
checkAndClose(requestId);
|
||||
finish();
|
||||
}).fail([=](const RPCError &error) {
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
data->requests.insert(history->sendRequestId);
|
||||
};
|
||||
|
||||
const auto forwardMediaUnquoted = [&] (not_null<HistoryItem *> item, not_null<History*> history) {
|
||||
const auto media = item->media();
|
||||
|
||||
auto newSendFlags = MTPmessages_SendMedia::Flags(0)
|
||||
| (options.silent
|
||||
? MTPmessages_SendMedia::Flag::f_silent
|
||||
: MTPmessages_SendMedia::Flag(0))
|
||||
| (options.scheduled
|
||||
? MTPmessages_SendMedia::Flag::f_schedule_date
|
||||
: MTPmessages_SendMedia::Flag(0));
|
||||
|
||||
const auto caption = (cForwardCaptioned()
|
||||
&& !media->geoPoint()
|
||||
&& !media->sharedContact())
|
||||
? item->originalText()
|
||||
: TextWithEntities();
|
||||
|
||||
const auto sentEntities = Api::EntitiesToMTP(
|
||||
session,
|
||||
caption.entities,
|
||||
Api::ConvertOption::SkipLocal);
|
||||
if (!sentEntities.v.isEmpty()) {
|
||||
newSendFlags |= MTPmessages_SendMedia::Flag::f_entities;
|
||||
}
|
||||
|
||||
const auto inputMedia = media->poll()
|
||||
? PollDataToInputMedia(media->poll())
|
||||
: media->geoPoint()
|
||||
? MTP_inputMediaGeoPoint(
|
||||
MTP_inputGeoPoint(
|
||||
MTP_double(media->geoPoint()->lat()),
|
||||
MTP_double(media->geoPoint()->lon())))
|
||||
: media->sharedContact()
|
||||
? MTP_inputMediaContact(
|
||||
MTP_string(media->sharedContact()->phoneNumber),
|
||||
MTP_string(media->sharedContact()->firstName),
|
||||
MTP_string(media->sharedContact()->lastName),
|
||||
MTPstring())
|
||||
: media->photo()
|
||||
? MTP_inputMediaPhoto(MTP_flags(0), media->photo()->mtpInput(), MTPint())
|
||||
: MTP_inputMediaDocument(MTP_flags(0), media->document()->mtpInput(), MTPint());
|
||||
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
auto &api = history->session().api();
|
||||
history->sendRequestId = api.request(MTPmessages_SendMedia(
|
||||
MTP_flags(newSendFlags),
|
||||
history->peer->input,
|
||||
MTPint(),
|
||||
inputMedia,
|
||||
MTP_string(caption.text),
|
||||
rand_value<MTPlong>(),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(options.scheduled)
|
||||
)).done([=](const MTPUpdates &updates, mtpRequestId requestId) {
|
||||
history->session().api().applyUpdates(updates);
|
||||
checkAndClose(requestId);
|
||||
finish();
|
||||
}).fail([=](const RPCError &error) {
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
data->requests.insert(history->sendRequestId);
|
||||
};
|
||||
|
||||
const auto forwardMessageUnquoted = [&] (not_null<HistoryItem *> item, not_null<History*> history) {
|
||||
const auto media = item->media();
|
||||
|
||||
auto newSendFlags = MTPmessages_SendMessage::Flag(0)
|
||||
| (!media || !media->webpage()
|
||||
? MTPmessages_SendMessage::Flag::f_no_webpage
|
||||
: MTPmessages_SendMessage::Flag(0))
|
||||
| (options.silent
|
||||
? MTPmessages_SendMessage::Flag::f_silent
|
||||
: MTPmessages_SendMessage::Flag(0))
|
||||
| (options.scheduled
|
||||
? MTPmessages_SendMessage::Flag::f_schedule_date
|
||||
: MTPmessages_SendMessage::Flag(0));
|
||||
|
||||
const auto sentEntities = Api::EntitiesToMTP(
|
||||
session,
|
||||
item->originalText().entities,
|
||||
Api::ConvertOption::SkipLocal);
|
||||
if (!sentEntities.v.isEmpty()) {
|
||||
newSendFlags |= MTPmessages_SendMessage::Flag::f_entities;
|
||||
}
|
||||
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
auto &api = history->session().api();
|
||||
history->sendRequestId = api.request(MTPmessages_SendMessage(
|
||||
MTP_flags(newSendFlags),
|
||||
history->peer->input,
|
||||
MTPint(),
|
||||
MTP_string(item->originalText().text),
|
||||
rand_value<MTPlong>(),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(options.scheduled)
|
||||
)).done([=](const MTPUpdates &updates, mtpRequestId requestId) {
|
||||
history->session().api().applyUpdates(updates);
|
||||
checkAndClose(requestId);
|
||||
finish();
|
||||
}).fail([=](const RPCError &error) {
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
data->requests.insert(history->sendRequestId);
|
||||
};
|
||||
|
||||
for (const auto peer : result) {
|
||||
const auto history = owner->history(peer);
|
||||
if (!comment.text.isEmpty()) {
|
||||
@ -1168,30 +1419,39 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
||||
message.action.clearDraft = false;
|
||||
api.sendMessage(std::move(message));
|
||||
}
|
||||
for (auto group : groupedMsgIds) {
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
auto &api = history->session().api();
|
||||
history->sendRequestId = api.request(MTPmessages_ForwardMessages(
|
||||
MTP_flags(group.grouped ? groupedSendFlags : sendFlags),
|
||||
data->peer->input,
|
||||
MTP_vector<MTPint>(group.ids),
|
||||
MTP_vector<MTPlong>(generateRandom(group.ids.size())),
|
||||
peer->input,
|
||||
MTP_int(options.scheduled)
|
||||
)).done([=](const MTPUpdates &updates, mtpRequestId requestId) {
|
||||
history->session().api().applyUpdates(updates);
|
||||
data->requests.remove(requestId);
|
||||
if (data->requests.empty()) {
|
||||
Ui::Toast::Show(tr::lng_share_done(tr::now));
|
||||
Ui::hideLayer();
|
||||
for (auto &group : groupedMsgIds) {
|
||||
if (cForwardQuoted()) {
|
||||
// Forward regrouped messages as is
|
||||
const auto flags = group.grouped ? groupedSendFlags : sendFlags;
|
||||
forwardQuoted(std::move(group), history, flags);
|
||||
} else if (group.grouped) {
|
||||
// Sending albums without author
|
||||
forwardAlbumUnquoted(std::move(group), history);
|
||||
} else {
|
||||
for (const auto item : group.items) {
|
||||
const auto media = item->media();
|
||||
|
||||
if (media && !media->webpage()) {
|
||||
if (media->poll()
|
||||
|| media->geoPoint()
|
||||
|| media->sharedContact()
|
||||
|| media->photo()
|
||||
|| media->document()) {
|
||||
// Send media messages without author
|
||||
forwardMediaUnquoted(item, history);
|
||||
} else {
|
||||
// Forward message if type doesn't support forwarding unquoted
|
||||
forwardQuoted(
|
||||
MsgIdsGroup(item, MTP_int(item->fullId().msg)),
|
||||
history,
|
||||
sendFlags);
|
||||
}
|
||||
} else {
|
||||
// Send messages without author
|
||||
forwardMessageUnquoted(item, history);
|
||||
}
|
||||
finish();
|
||||
}).fail([=](const RPCError &error) {
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
data->requests.insert(history->sendRequestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data->submitCallback && !cForwardRetainSelection()) {
|
||||
@ -1212,7 +1472,8 @@ QPointer<Ui::RpWidget> ShowForwardMessagesBox(
|
||||
std::move(copyLinkCallback),
|
||||
std::move(submitCallback),
|
||||
std::move(filterCallback),
|
||||
std::move(goToChatCallback)));
|
||||
std::move(goToChatCallback),
|
||||
hasMediaForGrouping));
|
||||
return weak->data();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user