Fix sending many files with a comment.

This commit is contained in:
John Preston 2020-10-17 12:51:55 +03:00
parent 85d08c8f52
commit bb4fdde616
15 changed files with 246 additions and 295 deletions

View file

@ -4212,14 +4212,12 @@ void ApiWrap::sendFiles(
std::shared_ptr<SendingAlbum> album, std::shared_ptr<SendingAlbum> album,
const SendAction &action) { const SendAction &action) {
const auto haveCaption = !caption.text.isEmpty(); const auto haveCaption = !caption.text.isEmpty();
const auto isAlbum = (album != nullptr); if (haveCaption && !list.canAddCaption(album != nullptr)) {
if (haveCaption && !list.canAddCaption(isAlbum)) {
auto message = MessageToSend(action.history); auto message = MessageToSend(action.history);
message.textWithTags = std::move(caption); message.textWithTags = base::take(caption);
message.action = action; message.action = action;
message.action.clearDraft = false; message.action.clearDraft = false;
sendMessage(std::move(message)); sendMessage(std::move(message));
caption = TextWithTags();
} }
const auto to = fileLoadTaskOptions(action); const auto to = fileLoadTaskOptions(action);
@ -4240,7 +4238,7 @@ void ApiWrap::sendFiles(
case Ui::PreparedFile::AlbumType::File: case Ui::PreparedFile::AlbumType::File:
type = SendMediaType::File; type = SendMediaType::File;
break; break;
default: Unexpected("AlbumType in uploadFilesAfterConfirmation"); default: Unexpected("AlbumType in ApiWrap::sendFiles.");
} }
} }
tasks.push_back(std::make_unique<FileLoadTask>( tasks.push_back(std::make_unique<FileLoadTask>(

View file

@ -94,7 +94,7 @@ void FileDialogCallback(
rpl::producer<QString> FieldPlaceholder( rpl::producer<QString> FieldPlaceholder(
const Ui::PreparedList &list, const Ui::PreparedList &list,
SendFilesWay way) { SendFilesWay way) {
return list.canAddCaption(way.groupMediaInAlbums()) return list.canAddCaption(way.groupFiles() && way.sendImagesAsPhotos())
? tr::lng_photo_caption() ? tr::lng_photo_caption()
: tr::lng_photos_comment(); : tr::lng_photos_comment();
} }
@ -436,7 +436,6 @@ void SendFilesBox::initSendWay() {
_sendWay = [&] { _sendWay = [&] {
auto result = Core::App().settings().sendFilesWay(); auto result = Core::App().settings().sendFilesWay();
if (_sendLimit == SendLimit::One) { if (_sendLimit == SendLimit::One) {
result.setGroupMediaInAlbums(true);
result.setGroupFiles(true); result.setGroupFiles(true);
return result; return result;
} else if (_list.overrideSendImagesAsPhotos == false) { } else if (_list.overrideSendImagesAsPhotos == false) {
@ -463,15 +462,15 @@ void SendFilesBox::updateCaptionPlaceholder() {
if (!_caption) { if (!_caption) {
return; return;
} }
const auto sendWay = _sendWay.current(); const auto way = _sendWay.current();
if (!_list.canAddCaption(sendWay.groupMediaInAlbums()) if (!_list.canAddCaption(way.groupFiles() && way.sendImagesAsPhotos())
&& _sendLimit == SendLimit::One) { && _sendLimit == SendLimit::One) {
_caption->hide(); _caption->hide();
if (_emojiToggle) { if (_emojiToggle) {
_emojiToggle->hide(); _emojiToggle->hide();
} }
} else { } else {
_caption->setPlaceholder(FieldPlaceholder(_list, sendWay)); _caption->setPlaceholder(FieldPlaceholder(_list, way));
_caption->show(); _caption->show();
if (_emojiToggle) { if (_emojiToggle) {
_emojiToggle->show(); _emojiToggle->show();
@ -544,33 +543,27 @@ void SendFilesBox::refreshControls() {
void SendFilesBox::setupSendWayControls() { void SendFilesBox::setupSendWayControls() {
// #TODO files // #TODO files
_groupMediaInAlbums.create( _groupFiles.create(
this, this,
"Group media in albums", "Group items",
_sendWay.current().groupMediaInAlbums(), _sendWay.current().groupFiles(),
st::defaultBoxCheckbox); st::defaultBoxCheckbox);
_sendImagesAsPhotos.create( _sendImagesAsPhotos.create(
this, this,
"Send images as photos", "Compress images",
_sendWay.current().sendImagesAsPhotos(), _sendWay.current().sendImagesAsPhotos(),
st::defaultBoxCheckbox); st::defaultBoxCheckbox);
_groupFiles.create(
this,
"Group files",
_sendWay.current().groupFiles(),
st::defaultBoxCheckbox);
_sendWay.changes( _sendWay.changes(
) | rpl::start_with_next([=](SendFilesWay value) { ) | rpl::start_with_next([=](SendFilesWay value) {
_groupMediaInAlbums->setChecked(value.groupMediaInAlbums());
_sendImagesAsPhotos->setChecked(value.sendImagesAsPhotos());
_groupFiles->setChecked(value.groupFiles()); _groupFiles->setChecked(value.groupFiles());
_sendImagesAsPhotos->setChecked(value.sendImagesAsPhotos());
}, lifetime()); }, lifetime());
_groupMediaInAlbums->checkedChanges( _groupFiles->checkedChanges(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
auto sendWay = _sendWay.current(); auto sendWay = _sendWay.current();
sendWay.setGroupMediaInAlbums(_groupMediaInAlbums->checked()); sendWay.setGroupFiles(_groupFiles->checked());
_sendWay = sendWay; _sendWay = sendWay;
}, lifetime()); }, lifetime());
@ -580,13 +573,6 @@ void SendFilesBox::setupSendWayControls() {
sendWay.setSendImagesAsPhotos(_sendImagesAsPhotos->checked()); sendWay.setSendImagesAsPhotos(_sendImagesAsPhotos->checked());
_sendWay = sendWay; _sendWay = sendWay;
}, lifetime()); }, lifetime());
_groupFiles->checkedChanges(
) | rpl::start_with_next([=] {
auto sendWay = _sendWay.current();
sendWay.setGroupFiles(_groupFiles->checked());
_sendWay = sendWay;
}, lifetime());
} }
void SendFilesBox::updateSendWayControlsVisibility() { void SendFilesBox::updateSendWayControlsVisibility() {
@ -594,9 +580,8 @@ void SendFilesBox::updateSendWayControlsVisibility() {
return; return;
} }
const auto onlyOne = (_sendLimit == SendLimit::One); const auto onlyOne = (_sendLimit == SendLimit::One);
_groupMediaInAlbums->setVisible(!onlyOne);
_sendImagesAsPhotos->setVisible(/*_list.hasImagesForCompression()*/true); // #TODO files
_groupFiles->setVisible(!onlyOne); _groupFiles->setVisible(!onlyOne);
_sendImagesAsPhotos->setVisible(/*_list.hasImagesForCompression()*/true); // #TODO files
} }
void SendFilesBox::setupCaption() { void SendFilesBox::setupCaption() {
@ -798,9 +783,8 @@ void SendFilesBox::updateBoxSize() {
footerHeight += st::boxPhotoCaptionSkip + _caption->height(); footerHeight += st::boxPhotoCaptionSkip + _caption->height();
} }
const auto pointers = { const auto pointers = {
_groupMediaInAlbums.data(), _groupFiles.data(),
_sendImagesAsPhotos.data(), _sendImagesAsPhotos.data(),
_groupFiles.data()
}; };
for (auto pointer : pointers) { for (auto pointer : pointers) {
if (pointer && !pointer->isHidden()) { if (pointer && !pointer->isHidden()) {
@ -864,9 +848,8 @@ void SendFilesBox::updateControlsGeometry() {
} }
} }
const auto pointers = { const auto pointers = {
_groupMediaInAlbums.data(), _groupFiles.data(),
_sendImagesAsPhotos.data(), _sendImagesAsPhotos.data(),
_groupFiles.data()
}; };
for (const auto pointer : ranges::view::reverse(pointers)) { for (const auto pointer : ranges::view::reverse(pointers)) {
if (pointer && !pointer->isHidden()) { if (pointer && !pointer->isHidden()) {
@ -905,16 +888,13 @@ void SendFilesBox::send(
auto way = _sendWay.current(); auto way = _sendWay.current();
auto oldWay = Core::App().settings().sendFilesWay(); auto oldWay = Core::App().settings().sendFilesWay();
if (_groupFiles->isHidden()) {
way.setGroupFiles(oldWay.groupFiles());
}
if (_list.overrideSendImagesAsPhotos == way.sendImagesAsPhotos() if (_list.overrideSendImagesAsPhotos == way.sendImagesAsPhotos()
|| _sendImagesAsPhotos->isHidden()) { || _sendImagesAsPhotos->isHidden()) {
way.setSendImagesAsPhotos(oldWay.sendImagesAsPhotos()); way.setSendImagesAsPhotos(oldWay.sendImagesAsPhotos());
} }
if (_groupMediaInAlbums->isHidden()) {
way.setGroupMediaInAlbums(oldWay.groupMediaInAlbums());
}
if (_groupFiles->isHidden()) {
way.setGroupFiles(oldWay.groupFiles());
}
if (way != oldWay) { if (way != oldWay) {
Core::App().settings().setSendFilesWay(way); Core::App().settings().setSendFilesWay(way);
Core::App().saveSettingsDelayed(); Core::App().saveSettingsDelayed();

View file

@ -176,9 +176,8 @@ private:
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel; base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
base::unique_qptr<QObject> _emojiFilter; base::unique_qptr<QObject> _emojiFilter;
object_ptr<Ui::Checkbox> _groupMediaInAlbums = { nullptr };
object_ptr<Ui::Checkbox> _sendImagesAsPhotos = { nullptr };
object_ptr<Ui::Checkbox> _groupFiles = { nullptr }; object_ptr<Ui::Checkbox> _groupFiles = { nullptr };
object_ptr<Ui::Checkbox> _sendImagesAsPhotos = { nullptr };
rpl::variable<Ui::SendFilesWay> _sendWay = Ui::SendFilesWay(); rpl::variable<Ui::SendFilesWay> _sendWay = Ui::SendFilesWay();
rpl::variable<int> _footerHeight = 0; rpl::variable<int> _footerHeight = 0;
@ -190,8 +189,6 @@ private:
Fn<void()> _whenReadySend; Fn<void()> _whenReadySend;
bool _preparing = false; bool _preparing = false;
int _lastScrollTop = 0;
QPointer<Ui::RoundButton> _send; QPointer<Ui::RoundButton> _send;
QPointer<Ui::RoundButton> _addFile; QPointer<Ui::RoundButton> _addFile;

View file

@ -4215,60 +4215,34 @@ void HistoryWidget::sendingFilesConfirmed(
if (showSendingFilesError(list)) { if (showSendingFilesError(list)) {
return; return;
} }
const auto slowmode = _peer->slowmodeApplied(); auto groups = DivideByGroups(
const auto sendImagesAsPhotos = way.sendImagesAsPhotos(); std::move(list),
const auto sendType = sendImagesAsPhotos way,
_peer->slowmodeApplied());
const auto type = way.sendImagesAsPhotos()
? SendMediaType::Photo ? SendMediaType::Photo
: SendMediaType::File; : SendMediaType::File;
const auto groupMedia = way.groupMediaInAlbums() || slowmode; auto action = Api::SendAction(_history);
const auto groupFiles = way.groupFiles() || slowmode; action.replyTo = replyToId();
action.options = options;
auto group = Ui::PreparedList(); action.clearDraft = false;
if (groups.size() > 1 && !caption.text.isEmpty()) {
// For groupType Type::Video means media album, auto message = Api::MessageToSend(_history);
// Type::File means file album, message.textWithTags = base::take(caption);
// Type::None means no grouping. message.action = action;
using Type = Ui::PreparedFile::AlbumType; session().api().sendMessage(std::move(message));
auto groupType = Type::None;
const auto reply = replyToId();
auto sendGroup = [&] {
if (group.files.empty()) {
return;
}
const auto album = (groupType == Type::None)
? nullptr
: std::make_shared<SendingAlbum>();
uploadFilesAfterConfirmation(
base::take(group),
sendType,
base::take(caption),
reply,
options,
std::move(album));
};
for (auto i = 0; i != list.files.size(); ++i) {
auto &file = list.files[i];
const auto fileGroupType = (file.type == Type::Video)
? (groupMedia ? Type::Video : Type::None)
: (file.type == Type::Photo)
? ((groupMedia && sendImagesAsPhotos)
? Type::Video
: (groupFiles && !sendImagesAsPhotos)
? Type::File
: Type::None)
: (file.type == Type::File)
? (groupFiles ? Type::File : Type::None)
: Type::None;
if ((!group.files.empty() && groupType != fileGroupType)
|| ((groupType != Type::None)
&& (group.files.size() == Ui::MaxAlbumItems()))) {
sendGroup();
}
group.files.push_back(std::move(file));
groupType = fileGroupType;
} }
sendGroup(); for (auto &group : groups) {
const auto album = group.grouped
? std::make_shared<SendingAlbum>()
: nullptr;
session().api().sendFiles(
std::move(group.list),
type,
base::take(caption),
album,
action);
};
} }
bool HistoryWidget::confirmSendingFiles( bool HistoryWidget::confirmSendingFiles(
@ -4343,38 +4317,6 @@ bool HistoryWidget::confirmSendingFiles(
return false; return false;
} }
void HistoryWidget::uploadFilesAfterConfirmation(
Ui::PreparedList &&list,
SendMediaType type,
TextWithTags &&caption,
MsgId replyTo,
Api::SendOptions options,
std::shared_ptr<SendingAlbum> album) {
Assert(canWriteMessage());
const auto isAlbum = (album != nullptr);
if (_peer->slowmodeApplied()
&& ((list.files.size() > 1 && !album)
|| (!list.files.empty()
&& !caption.text.isEmpty()
&& !list.canAddCaption(isAlbum)))) {
Ui::ShowMultilineToast({
.text = { tr::lng_slowmode_no_many(tr::now) },
});
return;
}
auto action = Api::SendAction(_history);
action.replyTo = replyTo;
action.options = options;
session().api().sendFiles(
std::move(list),
type,
std::move(caption),
album,
action);
}
void HistoryWidget::uploadFile( void HistoryWidget::uploadFile(
const QByteArray &fileContent, const QByteArray &fileContent,
SendMediaType type) { SendMediaType type) {

View file

@ -434,15 +434,6 @@ private:
bool ctrlShiftEnter); bool ctrlShiftEnter);
void uploadFile(const QByteArray &fileContent, SendMediaType type); void uploadFile(const QByteArray &fileContent, SendMediaType type);
void uploadFilesAfterConfirmation(
Ui::PreparedList &&list,
SendMediaType type,
TextWithTags &&caption,
MsgId replyTo,
Api::SendOptions options,
std::shared_ptr<SendingAlbum> album = nullptr);
void itemRemoved(not_null<const HistoryItem*> item); void itemRemoved(not_null<const HistoryItem*> item);
// Updates position of controls around the message field, // Updates position of controls around the message field,

View file

@ -621,25 +621,12 @@ bool RepliesWidget::confirmSendingFiles(
TextWithTags &&caption, TextWithTags &&caption,
Api::SendOptions options, Api::SendOptions options,
bool ctrlShiftEnter) { bool ctrlShiftEnter) {
if (showSendingFilesError(list)) { sendingFilesConfirmed(
return;
}
const auto type = way.sendImagesAsPhotos()
? SendMediaType::Photo
: SendMediaType::File;
const auto album = way.groupMediaInAlbums() // #TODO files
? std::make_shared<SendingAlbum>()
: nullptr;
uploadFilesAfterConfirmation(
std::move(list), std::move(list),
type, way,
std::move(caption), std::move(caption),
replyTo,
options, options,
album); ctrlShiftEnter);
if (_composeControls->replyingToMessage().msg == replyTo) {
_composeControls->cancelReplyMessage();
}
})); }));
box->setCancelledCallback(crl::guard(this, [=] { box->setCancelledCallback(crl::guard(this, [=] {
_composeControls->setText(text); _composeControls->setText(text);
@ -661,6 +648,51 @@ bool RepliesWidget::confirmSendingFiles(
return true; return true;
} }
void RepliesWidget::sendingFilesConfirmed(
Ui::PreparedList &&list,
Ui::SendFilesWay way,
TextWithTags &&caption,
Api::SendOptions options,
bool ctrlShiftEnter) {
Expects(list.filesToProcess.empty());
if (showSendingFilesError(list)) {
return;
}
auto groups = DivideByGroups(
std::move(list),
way,
_history->peer->slowmodeApplied());
const auto replyTo = replyToId();
const auto type = way.sendImagesAsPhotos()
? SendMediaType::Photo
: SendMediaType::File;
auto action = Api::SendAction(_history);
action.replyTo = replyTo ? replyTo : _rootId;
action.options = options;
action.clearDraft = false;
if (groups.size() > 1 && !caption.text.isEmpty()) {
auto message = Api::MessageToSend(_history);
message.textWithTags = base::take(caption);
message.action = action;
session().api().sendMessage(std::move(message));
}
for (auto &group : groups) {
const auto album = group.grouped
? std::make_shared<SendingAlbum>()
: nullptr;
session().api().sendFiles(
std::move(group.list),
type,
base::take(caption),
album,
action);
};
if (_composeControls->replyingToMessage().msg == replyTo) {
_composeControls->cancelReplyMessage();
}
}
bool RepliesWidget::confirmSendingFiles( bool RepliesWidget::confirmSendingFiles(
QImage &&image, QImage &&image,
QByteArray &&content, QByteArray &&content,
@ -708,35 +740,6 @@ std::optional<QString> RepliesWidget::writeRestriction() const {
ChatRestriction::f_send_messages); ChatRestriction::f_send_messages);
} }
void RepliesWidget::uploadFilesAfterConfirmation(
Ui::PreparedList &&list,
SendMediaType type,
TextWithTags &&caption,
MsgId replyTo,
Api::SendOptions options,
std::shared_ptr<SendingAlbum> album) {
const auto isAlbum = (album != nullptr);
if (_history->peer->slowmodeApplied()
&& ((list.files.size() > 1 && !album)
|| (!list.files.empty()
&& !caption.text.isEmpty()
&& !list.canAddCaption(isAlbum)))) {
Ui::ShowMultilineToast({
.text = { tr::lng_slowmode_no_many(tr::now) }
});
return;
}
auto action = Api::SendAction(_history);
action.replyTo = replyTo ? replyTo : _rootId;
action.options = options;
session().api().sendFiles(
std::move(list),
type,
std::move(caption),
album,
action);
}
void RepliesWidget::pushReplyReturn(not_null<HistoryItem*> item) { void RepliesWidget::pushReplyReturn(not_null<HistoryItem*> item) {
if (item->history() == _history && item->replyToTop() == _rootId) { if (item->history() == _history && item->replyToTop() == _rootId) {
_replyReturns.push_back(item->id); _replyReturns.push_back(item->id);

View file

@ -35,6 +35,7 @@ class FlatButton;
class HistoryDownButton; class HistoryDownButton;
class PinnedBar; class PinnedBar;
struct PreparedList; struct PreparedList;
class SendFilesWay;
} // namespace Ui } // namespace Ui
namespace Profile { namespace Profile {
@ -207,13 +208,12 @@ private:
std::optional<bool> overrideSendImagesAsPhotos = std::nullopt, std::optional<bool> overrideSendImagesAsPhotos = std::nullopt,
const QString &insertTextOnCancel = QString()); const QString &insertTextOnCancel = QString());
bool showSendingFilesError(const Ui::PreparedList &list) const; bool showSendingFilesError(const Ui::PreparedList &list) const;
void uploadFilesAfterConfirmation( void sendingFilesConfirmed(
Ui::PreparedList &&list, Ui::PreparedList &&list,
SendMediaType type, Ui::SendFilesWay way,
TextWithTags &&caption, TextWithTags &&caption,
MsgId replyTo,
Api::SendOptions options, Api::SendOptions options,
std::shared_ptr<SendingAlbum> album); bool ctrlShiftEnter);
void sendExistingDocument(not_null<DocumentData*> document); void sendExistingDocument(not_null<DocumentData*> document);
bool sendExistingDocument( bool sendExistingDocument(

View file

@ -362,22 +362,12 @@ bool ScheduledWidget::confirmSendingFiles(
TextWithTags &&caption, TextWithTags &&caption,
Api::SendOptions options, Api::SendOptions options,
bool ctrlShiftEnter) { bool ctrlShiftEnter) {
if (showSendingFilesError(list)) { sendingFilesConfirmed(
return;
}
const auto type = way.sendImagesAsPhotos()
? SendMediaType::Photo
: SendMediaType::File;
const auto album = way.groupMediaInAlbums() // #TODO files
? std::make_shared<SendingAlbum>()
: nullptr;
uploadFilesAfterConfirmation(
std::move(list), std::move(list),
type, way,
std::move(caption), std::move(caption),
MsgId(0),//replyToId(),
options, options,
album); ctrlShiftEnter);
})); }));
//box->setCancelledCallback(crl::guard(this, [=] { //box->setCancelledCallback(crl::guard(this, [=] {
// _field->setTextWithTags(text); // _field->setTextWithTags(text);
@ -399,6 +389,43 @@ bool ScheduledWidget::confirmSendingFiles(
return true; return true;
} }
void ScheduledWidget::sendingFilesConfirmed(
Ui::PreparedList &&list,
Ui::SendFilesWay way,
TextWithTags &&caption,
Api::SendOptions options,
bool ctrlShiftEnter) {
Expects(list.filesToProcess.empty());
if (showSendingFilesError(list)) {
return;
}
auto groups = DivideByGroups(std::move(list), way, false);
const auto type = way.sendImagesAsPhotos()
? SendMediaType::Photo
: SendMediaType::File;
auto action = Api::SendAction(_history);
action.options = options;
action.clearDraft = false;
if (groups.size() > 1 && !caption.text.isEmpty()) {
auto message = Api::MessageToSend(_history);
message.textWithTags = base::take(caption);
message.action = action;
session().api().sendMessage(std::move(message));
}
for (auto &group : groups) {
const auto album = group.grouped
? std::make_shared<SendingAlbum>()
: nullptr;
session().api().sendFiles(
std::move(list),
type,
base::take(caption),
album,
action);
};
}
bool ScheduledWidget::confirmSendingFiles( bool ScheduledWidget::confirmSendingFiles(
QImage &&image, QImage &&image,
QByteArray &&content, QByteArray &&content,
@ -416,35 +443,6 @@ bool ScheduledWidget::confirmSendingFiles(
return confirmSendingFiles(std::move(list), insertTextOnCancel); return confirmSendingFiles(std::move(list), insertTextOnCancel);
} }
void ScheduledWidget::uploadFilesAfterConfirmation(
Ui::PreparedList &&list,
SendMediaType type,
TextWithTags &&caption,
MsgId replyTo,
Api::SendOptions options,
std::shared_ptr<SendingAlbum> album) {
const auto isAlbum = (album != nullptr);
if (_history->peer->slowmodeApplied()
&& ((list.files.size() > 1 && !album)
|| (!list.files.empty()
&& !caption.text.isEmpty()
&& !list.canAddCaption(isAlbum)))) {
Ui::ShowMultilineToast({
.text = { tr::lng_slowmode_no_many(tr::now) },
});
return;
}
auto action = Api::SendAction(_history);
action.replyTo = replyTo;
action.options = options;
session().api().sendFiles(
std::move(list),
type,
std::move(caption),
album,
action);
}
void ScheduledWidget::uploadFile( void ScheduledWidget::uploadFile(
const QByteArray &fileContent, const QByteArray &fileContent,
SendMediaType type) { SendMediaType type) {

View file

@ -30,6 +30,7 @@ class PlainShadow;
class FlatButton; class FlatButton;
class HistoryDownButton; class HistoryDownButton;
struct PreparedList; struct PreparedList;
class SendFilesWay;
} // namespace Ui } // namespace Ui
namespace Profile { namespace Profile {
@ -173,13 +174,12 @@ private:
std::optional<bool> overrideSendImagesAsPhotos = std::nullopt, std::optional<bool> overrideSendImagesAsPhotos = std::nullopt,
const QString &insertTextOnCancel = QString()); const QString &insertTextOnCancel = QString());
bool showSendingFilesError(const Ui::PreparedList &list) const; bool showSendingFilesError(const Ui::PreparedList &list) const;
void uploadFilesAfterConfirmation( void sendingFilesConfirmed(
Ui::PreparedList &&list, Ui::PreparedList &&list,
SendMediaType type, Ui::SendFilesWay way,
TextWithTags &&caption, TextWithTags &&caption,
MsgId replyTo,
Api::SendOptions options, Api::SendOptions options,
std::shared_ptr<SendingAlbum> album); bool ctrlShiftEnter);
void sendExistingDocument(not_null<DocumentData*> document); void sendExistingDocument(not_null<DocumentData*> document);
bool sendExistingDocument( bool sendExistingDocument(

View file

@ -919,7 +919,7 @@ bool ReadSetting(
if (!CheckStreamStatus(stream)) return false; if (!CheckStreamStatus(stream)) return false;
auto way = Ui::SendFilesWay(); auto way = Ui::SendFilesWay();
way.setGroupMediaInAlbums(v == 1); way.setGroupFiles(v == 1);
way.setSendImagesAsPhotos(v == 1); way.setSendImagesAsPhotos(v == 1);
Core::App().settings().setSendFilesWay(way); Core::App().settings().setSendFilesWay(way);
context.legacyRead = true; context.legacyRead = true;

View file

@ -137,7 +137,7 @@ AlbumThumbnail *AlbumPreview::findThumb(QPoint position) const {
? st::sendMediaPreviewPhotoSkip ? st::sendMediaPreviewPhotoSkip
: st::sendMediaFileThumbSkip; : st::sendMediaFileThumbSkip;
auto find = [&](const auto &thumb) { auto find = [&](const auto &thumb) {
if (_sendWay.groupMediaInAlbums()) { if (_sendWay.groupFiles() && _sendWay.sendImagesAsPhotos()) {
return thumb->containsPoint(position); return thumb->containsPoint(position);
} else { } else {
const auto bottom = top + (isPhotosWay const auto bottom = top + (isPhotosWay
@ -258,13 +258,13 @@ void AlbumPreview::updateSizeAnimated(
void AlbumPreview::updateSize() { void AlbumPreview::updateSize() {
const auto newHeight = [&] { const auto newHeight = [&] {
if (_sendWay.groupMediaInAlbums()) { if (!_sendWay.sendImagesAsPhotos()) {
return int(std::round(_thumbsHeightAnimation.value( return _filesHeight;
_thumbsHeight))); } else if (!_sendWay.groupFiles()) {
} else if (_sendWay.sendImagesAsPhotos()) {
return _photosHeight; return _photosHeight;
} else { } else {
return _filesHeight; return int(std::round(_thumbsHeightAnimation.value(
_thumbsHeight)));
} }
}(); }();
if (height() != newHeight) { if (height() != newHeight) {
@ -275,12 +275,12 @@ void AlbumPreview::updateSize() {
void AlbumPreview::paintEvent(QPaintEvent *e) { void AlbumPreview::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
if (_sendWay.groupMediaInAlbums()) { if (!_sendWay.sendImagesAsPhotos()) {
paintAlbum(p); paintFiles(p, e->rect());
} else if (_sendWay.sendImagesAsPhotos()) { } else if (!_sendWay.groupFiles()) {
paintPhotos(p, e->rect()); paintPhotos(p, e->rect());
} else { } else {
paintFiles(p, e->rect()); paintAlbum(p);
} }
} }
@ -409,7 +409,8 @@ void AlbumPreview::mouseMoveEvent(QMouseEvent *e) {
applyCursor(style::cur_default); applyCursor(style::cur_default);
return; return;
} }
const auto isAlbum = _sendWay.groupMediaInAlbums(); const auto isAlbum = _sendWay.sendImagesAsPhotos()
&& _sendWay.groupFiles();
if (isAlbum && _draggedThumb) { if (isAlbum && _draggedThumb) {
const auto position = e->pos(); const auto position = e->pos();
_draggedThumb->moveInAlbum(position - _draggedStartPosition); _draggedThumb->moveInAlbum(position - _draggedStartPosition);

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "ui/chat/attach/attach_prepare.h" #include "ui/chat/attach/attach_prepare.h"
#include "ui/chat/attach/attach_send_files_way.h"
#include "core/mime_type.h" #include "core/mime_type.h"
namespace Ui { namespace Ui {
@ -21,7 +22,7 @@ PreparedFile::PreparedFile(const QString &path) : path(path) {
PreparedFile::PreparedFile(PreparedFile &&other) = default; PreparedFile::PreparedFile(PreparedFile &&other) = default;
PreparedFile &PreparedFile::operator=(PreparedFile && other) = default; PreparedFile &PreparedFile::operator=(PreparedFile &&other) = default;
PreparedFile::~PreparedFile() = default; PreparedFile::~PreparedFile() = default;
@ -90,7 +91,7 @@ bool PreparedList::canBeSentInSlowmodeWith(const PreparedList &other) const {
return !hasNonGrouping && (!hasFiles || !hasVideos); return !hasNonGrouping && (!hasFiles || !hasVideos);
} }
bool PreparedList::canAddCaption(bool groupMediaInAlbums) const { bool PreparedList::canAddCaption(bool sendingAlbum) const {
if (!filesToProcess.empty() if (!filesToProcess.empty()
|| files.empty() || files.empty()
|| files.size() > kMaxAlbumCount) { || files.size() > kMaxAlbumCount) {
@ -104,14 +105,18 @@ bool PreparedList::canAddCaption(bool groupMediaInAlbums) const {
qstr(".tgs"), qstr(".tgs"),
Qt::CaseInsensitive); Qt::CaseInsensitive);
return !isSticker; return !isSticker;
} else if (!groupMediaInAlbums) { } else if (!sendingAlbum) {
return false; return false;
} }
const auto hasFiles = ranges::contains( const auto hasFiles = ranges::contains(
files, files,
PreparedFile::AlbumType::File, PreparedFile::AlbumType::File,
&PreparedFile::type); &PreparedFile::type);
return !hasFiles; const auto hasNotGrouped = ranges::contains(
files,
PreparedFile::AlbumType::None,
&PreparedFile::type);
return !hasFiles && !hasNotGrouped;
} }
int MaxAlbumItems() { int MaxAlbumItems() {
@ -125,4 +130,53 @@ bool ValidateThumbDimensions(int width, int height) {
&& (height < 20 * width); && (height < 20 * width);
} }
std::vector<PreparedGroup> DivideByGroups(
PreparedList &&list,
SendFilesWay way,
bool slowmode) {
const auto sendImagesAsPhotos = way.sendImagesAsPhotos();
const auto groupFiles = way.groupFiles() || slowmode;
auto group = Ui::PreparedList();
// For groupType Type::Video means media album,
// Type::File means file album,
// Type::None means no grouping.
using Type = Ui::PreparedFile::AlbumType;
auto groupType = Type::None;
auto result = std::vector<PreparedGroup>();
auto pushGroup = [&] {
result.push_back(PreparedGroup{
.list = base::take(group),
.grouped = (groupType != Type::None)
});
};
for (auto i = 0; i != list.files.size(); ++i) {
auto &file = list.files[i];
const auto fileGroupType = (file.type == Type::Video)
? (groupFiles ? Type::Video : Type::None)
: (file.type == Type::Photo)
? ((groupFiles && sendImagesAsPhotos)
? Type::Video
: (groupFiles && !sendImagesAsPhotos)
? Type::File
: Type::None)
: (file.type == Type::File)
? (groupFiles ? Type::File : Type::None)
: Type::None;
if ((!group.files.empty() && groupType != fileGroupType)
|| ((groupType != Type::None)
&& (group.files.size() == Ui::MaxAlbumItems()))) {
pushGroup();
}
group.files.push_back(std::move(file));
groupType = fileGroupType;
}
if (!group.files.empty()) {
pushGroup();
}
return result;
}
} // namespace Ui } // namespace Ui

View file

@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui { namespace Ui {
class SendFilesWay;
struct PreparedFileInformation { struct PreparedFileInformation {
struct Image { struct Image {
QImage data; QImage data;
@ -37,11 +39,9 @@ struct PreparedFileInformation {
struct PreparedFile { struct PreparedFile {
// File-s can be grouped if 'groupFiles'. // File-s can be grouped if 'groupFiles'.
// File-s + Photo-s can be grouped if 'groupFiles && !sendImagesAsPhotos'. // File-s + Photo-s can be grouped if 'groupFiles && !sendImagesAsPhotos'.
// Photo-s can be grouped if '(groupFiles && !sendImagesAsPhotos) // Photo-s can be grouped if 'groupFiles'.
// || (groupMediaInAlbums && sendImagesAsPhotos)'. // Photo-s + Video-s can be grouped if 'groupFiles && sendImagesAsPhotos'.
// Photo-s + Video-s can be grouped if 'groupMediaInAlbums // Video-s can be grouped if 'groupFiles'.
// && sendImagesAsPhotos'.
// Video-s can be grouped if 'groupMediaInAlbums'.
enum class AlbumType { enum class AlbumType {
File, File,
Photo, Photo,
@ -77,12 +77,15 @@ struct PreparedList {
: error(error) : error(error)
, errorData(errorData) { , errorData(errorData) {
} }
PreparedList(PreparedList &&other) = default;
PreparedList &operator=(PreparedList &&other) = default;
[[nodiscard]] static PreparedList Reordered( [[nodiscard]] static PreparedList Reordered(
PreparedList &&list, PreparedList &&list,
std::vector<int> order); std::vector<int> order);
void mergeToEnd(PreparedList &&other, bool cutToAlbumSize = false); void mergeToEnd(PreparedList &&other, bool cutToAlbumSize = false);
[[nodiscard]] bool canAddCaption(bool groupMediaInAlbums) const; [[nodiscard]] bool canAddCaption(bool sendingAlbum) const;
[[nodiscard]] bool canBeSentInSlowmode() const; [[nodiscard]] bool canBeSentInSlowmode() const;
[[nodiscard]] bool canBeSentInSlowmodeWith( [[nodiscard]] bool canBeSentInSlowmodeWith(
const PreparedList &other) const; const PreparedList &other) const;
@ -94,6 +97,16 @@ struct PreparedList {
std::optional<bool> overrideSendImagesAsPhotos; std::optional<bool> overrideSendImagesAsPhotos;
}; };
struct PreparedGroup {
PreparedList list;
bool grouped = false;
};
[[nodiscard]] std::vector<PreparedGroup> DivideByGroups(
PreparedList &&list,
SendFilesWay way,
bool slowmode);
[[nodiscard]] int MaxAlbumItems(); [[nodiscard]] int MaxAlbumItems();
[[nodiscard]] bool ValidateThumbDimensions(int width, int height); [[nodiscard]] bool ValidateThumbDimensions(int width, int height);

View file

@ -9,19 +9,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui { namespace Ui {
void SendFilesWay::setGroupMediaInAlbums(bool value) {
if (value) {
_flags |= (Flag::GroupMediaInAlbums | Flag::SendImagesAsPhotos);
} else {
_flags &= ~Flag::GroupMediaInAlbums;
}
}
void SendFilesWay::setSendImagesAsPhotos(bool value) { void SendFilesWay::setSendImagesAsPhotos(bool value) {
if (value) { if (value) {
_flags |= Flag::SendImagesAsPhotos; _flags |= Flag::SendImagesAsPhotos;
} else { } else {
_flags &= ~(Flag::SendImagesAsPhotos | Flag::GroupMediaInAlbums); _flags &= ~Flag::SendImagesAsPhotos;
} }
} }
@ -40,36 +32,23 @@ void SendFilesWay::setGroupFiles(bool value) {
//}; //};
int32 SendFilesWay::serialize() const { int32 SendFilesWay::serialize() const {
auto result = groupMediaInAlbums() auto result = (sendImagesAsPhotos() && groupFiles())
? int32(0) ? int32(0)
: sendImagesAsPhotos() : sendImagesAsPhotos()
? int32(1) ? int32(1)
: groupFiles()
? int32(3)
: int32(2); : int32(2);
if (!groupFiles()) {
result |= 0x04;
}
return result; return result;
} }
std::optional<SendFilesWay> SendFilesWay::FromSerialized(int32 value) { std::optional<SendFilesWay> SendFilesWay::FromSerialized(int32 value) {
auto result = SendFilesWay(); if (value < 0 || value > 3) {
result.setGroupFiles(!(value & 0x04)); return std::nullopt;
value &= ~0x04;
switch (value) {
case 0:
result.setGroupMediaInAlbums(true);
result.setSendImagesAsPhotos(true);
break;
case 1:
result.setGroupMediaInAlbums(false);
result.setSendImagesAsPhotos(true);
break;
case 2:
result.setGroupMediaInAlbums(false);
result.setSendImagesAsPhotos(false);
break;
default: return std::nullopt;
} }
auto result = SendFilesWay();
result.setGroupFiles((value == 0) || (value == 3));
result.setSendImagesAsPhotos((value == 0) || (value == 1));
return result; return result;
} }

View file

@ -19,18 +19,14 @@ enum class AttachButtonType {
class SendFilesWay final { class SendFilesWay final {
public: public:
[[nodiscard]] bool groupMediaInAlbums() const { [[nodiscard]] bool groupFiles() const {
return (_flags & Flag::GroupMediaInAlbums) != 0; return (_flags & Flag::GroupFiles) != 0;
} }
[[nodiscard]] bool sendImagesAsPhotos() const { [[nodiscard]] bool sendImagesAsPhotos() const {
return (_flags & Flag::SendImagesAsPhotos) != 0; return (_flags & Flag::SendImagesAsPhotos) != 0;
} }
[[nodiscard]] bool groupFiles() const {
return (_flags & Flag::GroupFiles);
}
void setGroupMediaInAlbums(bool value);
void setSendImagesAsPhotos(bool value);
void setGroupFiles(bool value); void setGroupFiles(bool value);
void setSendImagesAsPhotos(bool value);
[[nodiscard]] inline bool operator<(const SendFilesWay &other) const { [[nodiscard]] inline bool operator<(const SendFilesWay &other) const {
return _flags < other._flags; return _flags < other._flags;
@ -57,11 +53,10 @@ public:
private: private:
enum class Flag : uchar { enum class Flag : uchar {
GroupMediaInAlbums = (1 << 0), GroupFiles = (1 << 0),
SendImagesAsPhotos = (1 << 1), SendImagesAsPhotos = (1 << 1),
GroupFiles = (1 << 2),
Default = GroupMediaInAlbums | SendImagesAsPhotos | GroupFiles, Default = GroupFiles | SendImagesAsPhotos,
}; };
friend inline constexpr bool is_flag_type(Flag) { return true; }; friend inline constexpr bool is_flag_type(Flag) { return true; };