Correctly check media when editing files.

This commit is contained in:
John Preston 2020-10-20 11:19:48 +03:00
parent c4af731b19
commit a614ccad97
16 changed files with 155 additions and 187 deletions

View file

@ -4228,18 +4228,11 @@ void ApiWrap::sendFiles(
tasks.reserve(list.files.size()); tasks.reserve(list.files.size());
for (auto &file : list.files) { for (auto &file : list.files) {
if (album) { if (album) {
switch (file.type) { if (file.type == Ui::PreparedFile::Type::Photo
case Ui::PreparedFile::AlbumType::Photo: && type != SendMediaType::File) {
type = (type == SendMediaType::File) type = SendMediaType::Photo;
? type } else {
: SendMediaType::Photo;
break;
case Ui::PreparedFile::AlbumType::Music:
case Ui::PreparedFile::AlbumType::Video:
case Ui::PreparedFile::AlbumType::File:
type = SendMediaType::File; type = SendMediaType::File;
break;
default: Unexpected("AlbumType in ApiWrap::sendFiles.");
} }
} }
tasks.push_back(std::make_unique<FileLoadTask>( tasks.push_back(std::make_unique<FileLoadTask>(

View file

@ -106,10 +106,23 @@ EditCaptionBox::EditCaptionBox(
Expects(item->media()->allowsEditCaption()); Expects(item->media()->allowsEditCaption());
_isAllowedEditMedia = item->media()->allowsEditMedia(); _isAllowedEditMedia = item->media()->allowsEditMedia();
_isAlbum = !item->groupId().empty();
auto dimensions = QSize(); auto dimensions = QSize();
const auto media = item->media(); const auto media = item->media();
if (!item->groupId().empty()) {
if (media->photo()) {
_albumType = Ui::AlbumType::PhotoVideo;
} else if (const auto document = media->document()) {
if (document->isVideoFile()) {
_albumType = Ui::AlbumType::PhotoVideo;
} else if (document->isSong()) {
_albumType = Ui::AlbumType::Music;
} else {
_albumType = Ui::AlbumType::File;
}
}
}
if (const auto photo = media->photo()) { if (const auto photo = media->photo()) {
_photoMedia = photo->createMediaView(); _photoMedia = photo->createMediaView();
_photoMedia->wanted(PhotoSize::Large, _msgId); _photoMedia->wanted(PhotoSize::Large, _msgId);
@ -503,7 +516,8 @@ void EditCaptionBox::updateEditPreview() {
if (const auto image = std::get_if<Info::Image>(fileMedia)) { if (const auto image = std::get_if<Info::Image>(fileMedia)) {
shouldAsDoc = !Ui::ValidateThumbDimensions( shouldAsDoc = !Ui::ValidateThumbDimensions(
image->data.width(), image->data.width(),
image->data.height()); image->data.height()
) || (_albumType == Ui::AlbumType::File);
if (shouldAsDoc) { if (shouldAsDoc) {
docPhotoSize.setWidth(image->data.width()); docPhotoSize.setWidth(image->data.width());
docPhotoSize.setHeight(image->data.height()); docPhotoSize.setHeight(image->data.height());
@ -554,7 +568,7 @@ void EditCaptionBox::updateEditPreview() {
_doc = true; _doc = true;
} }
const auto showCheckbox = _photo && !_isAlbum; const auto showCheckbox = _photo && (_albumType == Ui::AlbumType::None);
_wayWrap->toggle(showCheckbox, anim::type::instant); _wayWrap->toggle(showCheckbox, anim::type::instant);
if (!_doc) { if (!_doc) {
@ -604,14 +618,10 @@ void EditCaptionBox::createEditMediaButton() {
if (Core::IsMimeSticker(mime)) { if (Core::IsMimeSticker(mime)) {
showError(tr::lng_edit_media_invalid_file); showError(tr::lng_edit_media_invalid_file);
return false; return false;
} else if (_isAlbum) { // #TODO files edit in file-albums } else if (_albumType != Ui::AlbumType::None
if (!Core::IsMimeAcceptedForAlbum(mime) && !file.canBeInAlbumType(_albumType)) {
|| file.type == Ui::PreparedFile::AlbumType::File showError(tr::lng_edit_media_album_error);
|| file.type == Ui::PreparedFile::AlbumType::Music return false;
|| file.type == Ui::PreparedFile::AlbumType::None) {
showError(tr::lng_edit_media_album_error);
return false;
}
} }
return true; return true;
}; };
@ -622,14 +632,13 @@ void EditCaptionBox::createEditMediaButton() {
st::sendMediaPreviewSize); st::sendMediaPreviewSize);
if (list) { if (list) {
_preparedList = std::move(*list); setPreparedList(std::move(*list));
updateEditPreview();
} }
}; };
const auto buttonCallback = [=] { const auto buttonCallback = [=] {
const auto filters = _isAlbum const auto filters = (_albumType == Ui::AlbumType::PhotoVideo)
? FileDialog::AlbumFilesFilter() ? FileDialog::PhotoVideoFilesFilter()
: FileDialog::AllFilesFilter(); : FileDialog::AllFilesFilter();
FileDialog::GetOpenPath( FileDialog::GetOpenPath(
this, this,
@ -676,7 +685,7 @@ void EditCaptionBox::prepare() {
if (action == Ui::InputField::MimeAction::Check) { if (action == Ui::InputField::MimeAction::Check) {
if (!data->hasText() && !_isAllowedEditMedia) { if (!data->hasText() && !_isAllowedEditMedia) {
return false; return false;
} else if (Storage::ValidateDragData(data, _isAlbum)) { } else if (Storage::ValidateEditMediaDragData(data, _albumType)) {
return true; return true;
} }
return data->hasText(); return data->hasText();
@ -700,40 +709,32 @@ void EditCaptionBox::prepare() {
} }
bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) { bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) {
return setPreparedList(ListFromMimeData(data));
}
bool EditCaptionBox::setPreparedList(Ui::PreparedList &&list) {
if (!_isAllowedEditMedia) { if (!_isAllowedEditMedia) {
return false; return false;
} }
using Error = Ui::PreparedList::Error; using Error = Ui::PreparedList::Error;
using AlbumType = Ui::PreparedFile::AlbumType; using Type = Ui::PreparedFile::Type;
auto list = ListFromMimeData(data);
if (list.error != Error::None || list.files.empty()) { if (list.error != Error::None || list.files.empty()) {
return false; return false;
} }
auto file = &list.files.front();
const auto file = &list.files.front(); const auto invalidForAlbum = (_albumType != Ui::AlbumType::None)
if (_isAlbum && (file->type == AlbumType::File && !file->canBeInAlbumType(_albumType);
|| file->type == AlbumType::None if (_albumType == Ui::AlbumType::PhotoVideo) {
|| file->type == AlbumType::Music)) { using Video = Ui::PreparedFileInformation::Video;
const auto imageAsDoc = [&] { if (const auto video = std::get_if<Video>(&file->information->media)) {
using Info = Ui::PreparedFileInformation; video->isGifv = false;
const auto fileMedia = &file->information->media;
if (const auto image = std::get_if<Info::Image>(fileMedia)) {
return !Ui::ValidateThumbDimensions(
image->data.width(),
image->data.height());
}
return false;
}();
if (!data->hasText() || imageAsDoc) {
Ui::show(
Box<InformBox>(tr::lng_edit_media_album_error(tr::now)),
Ui::LayerOption::KeepOther);
} }
}
if (invalidForAlbum) {
Ui::Toast::Show(tr::lng_edit_media_album_error(tr::now));
return false; return false;
} }
_photo = _isImage = (file->type == AlbumType::Photo); _photo = _isImage = (file->type == Type::Photo);
_preparedList = std::move(list); _preparedList = std::move(list);
updateEditPreview(); updateEditPreview();
return true; return true;
@ -783,7 +784,7 @@ void EditCaptionBox::setupDragArea() {
auto enterFilter = [=](not_null<const QMimeData*> data) { auto enterFilter = [=](not_null<const QMimeData*> data) {
return !_isAllowedEditMedia return !_isAllowedEditMedia
? false ? false
: Storage::ValidateDragData(data, _isAlbum); : Storage::ValidateEditMediaDragData(data, _albumType);
}; };
// Avoid both drag areas appearing at one time. // Avoid both drag areas appearing at one time.
auto computeState = [=](const QMimeData *data) { auto computeState = [=](const QMimeData *data) {

View file

@ -33,6 +33,7 @@ class InputField;
class EmojiButton; class EmojiButton;
class IconButton; class IconButton;
class Checkbox; class Checkbox;
enum class AlbumType;
} // namespace Ui } // namespace Ui
namespace Window { namespace Window {
@ -93,6 +94,7 @@ private:
int errorTopSkip() const; int errorTopSkip() const;
void createEditMediaButton(); void createEditMediaButton();
bool setPreparedList(Ui::PreparedList &&list);
inline QString getNewMediaPath() { inline QString getNewMediaPath() {
return _preparedList.files.empty() return _preparedList.files.empty()
@ -138,8 +140,8 @@ private:
object_ptr<Ui::IconButton> _editMedia = nullptr; object_ptr<Ui::IconButton> _editMedia = nullptr;
Ui::SlideWrap<Ui::RpWidget> *_wayWrap = nullptr; Ui::SlideWrap<Ui::RpWidget> *_wayWrap = nullptr;
QString _newMediaPath; QString _newMediaPath;
Ui::AlbumType _albumType = Ui::AlbumType();
bool _isAllowedEditMedia = false; bool _isAllowedEditMedia = false;
bool _isAlbum = false;
bool _asFile = false; bool _asFile = false;
rpl::event_stream<> _editMediaClicks; rpl::event_stream<> _editMediaClicks;

View file

@ -473,7 +473,7 @@ void SendFilesBox::preparePreview() {
void SendFilesBox::generatePreviewFrom(int fromBlock) { void SendFilesBox::generatePreviewFrom(int fromBlock) {
Expects(fromBlock <= _blocks.size()); Expects(fromBlock <= _blocks.size());
using Type = Ui::PreparedFile::AlbumType; using Type = Ui::PreparedFile::Type;
const auto eraseFrom = _blocks.begin() + fromBlock; const auto eraseFrom = _blocks.begin() + fromBlock;
for (auto i = eraseFrom; i != _blocks.end(); ++i) { for (auto i = eraseFrom; i != _blocks.end(); ++i) {
@ -813,7 +813,7 @@ void SendFilesBox::refreshTitleText() {
if (count > 1) { if (count > 1) {
const auto imagesCount = ranges::count( const auto imagesCount = ranges::count(
_list.files, _list.files,
Ui::PreparedFile::AlbumType::Photo, Ui::PreparedFile::Type::Photo,
&Ui::PreparedFile::type); &Ui::PreparedFile::type);
_titleText = (imagesCount == count) _titleText = (imagesCount == count)
? tr::lng_send_images_selected(tr::now, lt_count, count) ? tr::lng_send_images_selected(tr::now, lt_count, count)

View file

@ -329,8 +329,9 @@ QString ImagesOrAllFilter() {
return ImagesFilter() + u";;"_q + AllFilesFilter(); return ImagesFilter() + u";;"_q + AllFilesFilter();
} }
QString AlbumFilesFilter() { QString PhotoVideoFilesFilter() {
return u"Image and Video Files (*.png *.jpg *.jpeg *.mp4 *.mov)"_q; return u"Image and Video Files (*.png *.jpg *.jpeg *.mp4 *.mov);;"_q
+ AllFilesFilter();
} }
namespace internal { namespace internal {

View file

@ -93,7 +93,7 @@ void GetFolder(
[[nodiscard]] QString ImagesFilter(); [[nodiscard]] QString ImagesFilter();
[[nodiscard]] QString AllOrImagesFilter(); [[nodiscard]] QString AllOrImagesFilter();
[[nodiscard]] QString ImagesOrAllFilter(); [[nodiscard]] QString ImagesOrAllFilter();
[[nodiscard]] QString AlbumFilesFilter(); [[nodiscard]] QString PhotoVideoFilesFilter();
namespace internal { namespace internal {

View file

@ -111,7 +111,7 @@ bool IsMimeSticker(const QString &mime) {
|| IsMimeStickerAnimated(mime); || IsMimeStickerAnimated(mime);
} }
bool IsMimeAcceptedForAlbum(const QString &mime) { bool IsMimeAcceptedForPhotoVideoAlbum(const QString &mime) {
return (mime == u"image/jpeg"_q) return (mime == u"image/jpeg"_q)
|| (mime == u"image/png"_q) || (mime == u"image/png"_q)
|| (mime == u"video/mp4"_q) || (mime == u"video/mp4"_q)

View file

@ -42,7 +42,7 @@ private:
[[nodiscard]] bool IsMimeStickerAnimated(const QString &mime); [[nodiscard]] bool IsMimeStickerAnimated(const QString &mime);
[[nodiscard]] bool IsMimeSticker(const QString &mime); [[nodiscard]] bool IsMimeSticker(const QString &mime);
[[nodiscard]] bool IsMimeAcceptedForAlbum(const QString &mime); [[nodiscard]] bool IsMimeAcceptedForPhotoVideoAlbum(const QString &mime);
[[nodiscard]] bool FileIsImage(const QString &name, const QString &mime); [[nodiscard]] bool FileIsImage(const QString &name, const QString &mime);

View file

@ -4226,14 +4226,15 @@ void HistoryWidget::sendingFilesConfirmed(
action.replyTo = replyToId(); action.replyTo = replyToId();
action.options = options; action.options = options;
action.clearDraft = false; action.clearDraft = false;
if ((groups.empty() || groups.size() > 1) && !caption.text.isEmpty()) { if ((groups.size() != 1 || !groups.front().sentWithCaption())
&& !caption.text.isEmpty()) {
auto message = Api::MessageToSend(_history); auto message = Api::MessageToSend(_history);
message.textWithTags = base::take(caption); message.textWithTags = base::take(caption);
message.action = action; message.action = action;
session().api().sendMessage(std::move(message)); session().api().sendMessage(std::move(message));
} }
for (auto &group : groups) { for (auto &group : groups) {
const auto album = group.grouped const auto album = (group.type != Ui::AlbumType::None)
? std::make_shared<SendingAlbum>() ? std::make_shared<SendingAlbum>()
: nullptr; : nullptr;
session().api().sendFiles( session().api().sendFiles(

View file

@ -671,14 +671,15 @@ void RepliesWidget::sendingFilesConfirmed(
action.replyTo = replyTo ? replyTo : _rootId; action.replyTo = replyTo ? replyTo : _rootId;
action.options = options; action.options = options;
action.clearDraft = false; action.clearDraft = false;
if ((groups.empty() || groups.size() > 1) && !caption.text.isEmpty()) { if ((groups.size() != 1 || !groups.front().sentWithCaption())
&& !caption.text.isEmpty()) {
auto message = Api::MessageToSend(_history); auto message = Api::MessageToSend(_history);
message.textWithTags = base::take(caption); message.textWithTags = base::take(caption);
message.action = action; message.action = action;
session().api().sendMessage(std::move(message)); session().api().sendMessage(std::move(message));
} }
for (auto &group : groups) { for (auto &group : groups) {
const auto album = group.grouped const auto album = (group.type != Ui::AlbumType::None)
? std::make_shared<SendingAlbum>() ? std::make_shared<SendingAlbum>()
: nullptr; : nullptr;
session().api().sendFiles( session().api().sendFiles(

View file

@ -407,14 +407,15 @@ void ScheduledWidget::sendingFilesConfirmed(
auto action = Api::SendAction(_history); auto action = Api::SendAction(_history);
action.options = options; action.options = options;
action.clearDraft = false; action.clearDraft = false;
if ((groups.empty() || groups.size() > 1) && !caption.text.isEmpty()) { if ((groups.size() != 1 || !groups.front().sentWithCaption())
&& !caption.text.isEmpty()) {
auto message = Api::MessageToSend(_history); auto message = Api::MessageToSend(_history);
message.textWithTags = base::take(caption); message.textWithTags = base::take(caption);
message.action = action; message.action = action;
session().api().sendMessage(std::move(message)); session().api().sendMessage(std::move(message));
} }
for (auto &group : groups) { for (auto &group : groups) {
const auto album = group.grouped const auto album = (group.type != Ui::AlbumType::None)
? std::make_shared<SendingAlbum>() ? std::make_shared<SendingAlbum>()
: nullptr; : nullptr;
session().api().sendFiles( session().api().sendFiles(

View file

@ -80,19 +80,21 @@ void PrepareDetailsInParallel(PreparedList &result, int previewWidth) {
} // namespace } // namespace
bool ValidateDragData(not_null<const QMimeData*> data, bool isAlbum) { bool ValidateEditMediaDragData(
not_null<const QMimeData*> data,
Ui::AlbumType albumType) {
if (data->urls().size() > 1) { if (data->urls().size() > 1) {
return false; return false;
} else if (data->hasImage()) { } else if (data->hasImage()) {
return true; return (albumType != Ui::AlbumType::Music);
} }
if (isAlbum && data->hasUrls()) { if (albumType == Ui::AlbumType::PhotoVideo && data->hasUrls()) {
const auto url = data->urls().front(); const auto url = data->urls().front();
if (url.isLocalFile()) { if (url.isLocalFile()) {
using namespace Core; using namespace Core;
const auto info = QFileInfo(Platform::File::UrlToLocal(url)); const auto info = QFileInfo(Platform::File::UrlToLocal(url));
return IsMimeAcceptedForAlbum(MimeTypeForFile(info).name()); return IsMimeAcceptedForPhotoVideoAlbum(MimeTypeForFile(info).name());
} }
} }
@ -241,86 +243,6 @@ std::optional<PreparedList> PreparedFileFromFilesDialog(
} else { } else {
return list; return list;
} }
//if (!result.remoteContent.isEmpty()) {
// auto list = PrepareMediaFromImage(
// QImage(),
// std::move(result.remoteContent),
// previewWidth);
// const auto mimeFile = list.files.front().information->filemime;
// if (Core::IsMimeSticker(mimeFile)) {
// errorCallback(tr::lng_edit_media_invalid_file);
// return std::nullopt;
// }
// if (isAlbum) {
// const auto file = &list.files.front();
// if (!Core::IsMimeAcceptedForAlbum(mimeFile)
// || file->type == PreparedFile::AlbumType::File
// || file->type == PreparedFile::AlbumType::Music
// || file->type == PreparedFile::AlbumType::None) {
// errorCallback(tr::lng_edit_media_album_error);
// return std::nullopt;
// }
// }
// Ensures(list.files.size() == 1);
// return list;
//} else if (!result.paths.isEmpty()) {
// auto temp = PrepareMediaList(result.paths, previewWidth);
// const auto isSingleFile = (temp.files.size() == 1);
// if (temp.error != PreparedList::Error::None) {
// errorCallback(tr::lng_send_media_invalid_files);
// return std::nullopt;
// }
// auto filteredFiles = ranges::view::all(
// temp.files
// ) | ranges::view::filter([&](const auto &file) {
// const auto info = QFileInfo(file.path);
// if (Core::IsMimeSticker(Core::MimeTypeForFile(info).name())) {
// if (isSingleFile) {
// errorCallback(tr::lng_edit_media_invalid_file);
// }
// return false;
// }
// if (!isAlbum) {
// return true;
// }
// using Info = PreparedFileInformation;
// const auto media = &file.information->media;
// const auto valid = v::match(*media, [](const Info::Image &data) {
// return Ui::ValidateThumbDimensions(
// data.data.width(),
// data.data.height())
// && !data.animated;
// }, [](Info::Video &data) {
// data.isGifv = false;
// return true;
// }, [](auto &&other) {
// return false;
// });
// if (!valid && isSingleFile) {
// errorCallback(tr::lng_edit_media_album_error);
// }
// return valid;
// }) | ranges::view::transform([](auto &file) {
// return std::move(file);
// }) | ranges::to_vector;
// if (!filteredFiles.size()) {
// if (!isSingleFile) {
// errorCallback(tr::lng_send_media_invalid_files);
// }
// return std::nullopt;
// }
// auto list = PreparedList(temp.error, temp.errorData);
// list.files = std::move(filteredFiles);
// return list;
//}
//return std::nullopt;
} }
void PrepareDetails(PreparedFile &file, int previewWidth) { void PrepareDetails(PreparedFile &file, int previewWidth) {
@ -351,9 +273,9 @@ void PrepareDetails(PreparedFile &file, int previewWidth) {
Qt::SmoothTransformation)); Qt::SmoothTransformation));
Assert(!file.preview.isNull()); Assert(!file.preview.isNull());
file.preview.setDevicePixelRatio(cRetinaFactor()); file.preview.setDevicePixelRatio(cRetinaFactor());
file.type = PreparedFile::AlbumType::Photo; file.type = PreparedFile::Type::Photo;
} else if (Core::IsMimeSticker(file.information->filemime)) { } else if (Core::IsMimeSticker(file.information->filemime)) {
file.type = PreparedFile::AlbumType::None; file.type = PreparedFile::Type::None;
} }
} else if (const auto video = std::get_if<Video>( } else if (const auto video = std::get_if<Video>(
&file.information->media)) { &file.information->media)) {
@ -365,10 +287,10 @@ void PrepareDetails(PreparedFile &file, int previewWidth) {
Qt::SmoothTransformation); Qt::SmoothTransformation);
Assert(!file.preview.isNull()); Assert(!file.preview.isNull());
file.preview.setDevicePixelRatio(cRetinaFactor()); file.preview.setDevicePixelRatio(cRetinaFactor());
file.type = PreparedFile::AlbumType::Video; file.type = PreparedFile::Type::Video;
} }
} else if (const auto song = std::get_if<Song>(&file.information->media)) { } else if (const auto song = std::get_if<Song>(&file.information->media)) {
file.type = PreparedFile::AlbumType::Music; file.type = PreparedFile::Type::Music;
} }
} }

View file

@ -14,6 +14,7 @@ namespace Ui {
struct PreparedFileInformation; struct PreparedFileInformation;
struct PreparedFile; struct PreparedFile;
struct PreparedList; struct PreparedList;
enum class AlbumType;
} // namespace Ui } // namespace Ui
namespace Storage { namespace Storage {
@ -31,7 +32,9 @@ std::optional<Ui::PreparedList> PreparedFileFromFilesDialog(
Fn<void(tr::phrase<>)> errorCallback, Fn<void(tr::phrase<>)> errorCallback,
int previewWidth); int previewWidth);
MimeDataState ComputeMimeDataState(const QMimeData *data); MimeDataState ComputeMimeDataState(const QMimeData *data);
bool ValidateDragData(not_null<const QMimeData*> data, bool isAlbum); bool ValidateEditMediaDragData(
not_null<const QMimeData*> data,
Ui::AlbumType albumType);
Ui::PreparedList PrepareMediaList(const QList<QUrl> &files, int previewWidth); Ui::PreparedList PrepareMediaList(const QList<QUrl> &files, int previewWidth);
Ui::PreparedList PrepareMediaList(const QStringList &files, int previewWidth); Ui::PreparedList PrepareMediaList(const QStringList &files, int previewWidth);
Ui::PreparedList PrepareMediaFromImage( Ui::PreparedList PrepareMediaFromImage(

View file

@ -29,7 +29,7 @@ AlbumThumbnail::AlbumThumbnail(
: _layout(layout) : _layout(layout)
, _fullPreview(file.preview) , _fullPreview(file.preview)
, _shrinkSize(int(std::ceil(st::historyMessageRadius / 1.4))) , _shrinkSize(int(std::ceil(st::historyMessageRadius / 1.4)))
, _isVideo(file.type == PreparedFile::AlbumType::Video) , _isVideo(file.type == PreparedFile::Type::Video)
, _buttonsRect(st::sendBoxAlbumGroupRadius, st::callFingerprintBg) { , _buttonsRect(st::sendBoxAlbumGroupRadius, st::callFingerprintBg) {
Expects(!_fullPreview.isNull()); Expects(!_fullPreview.isNull());

View file

@ -26,6 +26,41 @@ PreparedFile &PreparedFile::operator=(PreparedFile &&other) = default;
PreparedFile::~PreparedFile() = default; PreparedFile::~PreparedFile() = default;
bool PreparedFile::canBeInAlbumType(AlbumType album) const {
return CanBeInAlbumType(type, album);
}
AlbumType PreparedFile::albumType(bool sendImagesAsPhotos) const {
switch (type) {
case Type::Photo:
return sendImagesAsPhotos ? AlbumType::PhotoVideo : AlbumType::File;
case Type::Video:
return AlbumType::PhotoVideo;
case Type::Music:
return AlbumType::Music;
case Type::File:
return AlbumType::File;
case Type::None:
return AlbumType::None;
}
Unexpected("PreparedFile::type in PreparedFile::albumType().");
}
bool CanBeInAlbumType(PreparedFile::Type type, AlbumType album) {
Expects(album != AlbumType::None);
using Type = PreparedFile::Type;
switch (album) {
case AlbumType::PhotoVideo:
return (type == Type::Photo) || (type == Type::Video);
case AlbumType::Music:
return (type == Type::Music);
case AlbumType::File:
return (type == Type::Photo) || (type == Type::File);
}
Unexpected("AlbumType in CanBeInAlbumType.");
}
PreparedList PreparedList::Reordered( PreparedList PreparedList::Reordered(
PreparedList &&list, PreparedList &&list,
std::vector<int> order) { std::vector<int> order) {
@ -73,7 +108,7 @@ bool PreparedList::canBeSentInSlowmodeWith(const PreparedList &other) const {
return false; return false;
} }
using Type = PreparedFile::AlbumType; using Type = PreparedFile::Type;
auto &&all = ranges::view::concat(files, other.files); auto &&all = ranges::view::concat(files, other.files);
const auto has = [&](Type type) { const auto has = [&](Type type) {
return ranges::contains(all, type, &PreparedFile::type); return ranges::contains(all, type, &PreparedFile::type);
@ -117,11 +152,11 @@ bool PreparedList::canAddCaption(bool sendingAlbum) const {
} }
const auto hasFiles = ranges::contains( const auto hasFiles = ranges::contains(
files, files,
PreparedFile::AlbumType::File, PreparedFile::Type::File,
&PreparedFile::type); &PreparedFile::type);
const auto hasNotGrouped = ranges::contains( const auto hasNotGrouped = ranges::contains(
files, files,
PreparedFile::AlbumType::None, PreparedFile::Type::None,
&PreparedFile::type); &PreparedFile::type);
return !hasFiles && !hasNotGrouped; return !hasFiles && !hasNotGrouped;
} }
@ -130,7 +165,7 @@ bool PreparedList::hasGroupOption(bool slowmode) const {
if (slowmode || files.size() < 2) { if (slowmode || files.size() < 2) {
return false; return false;
} }
using Type = PreparedFile::AlbumType; using Type = PreparedFile::Type;
auto lastType = Type::None; auto lastType = Type::None;
for (const auto &file : files) { for (const auto &file : files) {
if ((file.type == lastType) if ((file.type == lastType)
@ -148,7 +183,7 @@ bool PreparedList::hasGroupOption(bool slowmode) const {
} }
bool PreparedList::hasSendImagesAsPhotosOption(bool slowmode) const { bool PreparedList::hasSendImagesAsPhotosOption(bool slowmode) const {
using Type = PreparedFile::AlbumType; using Type = PreparedFile::Type;
return slowmode return slowmode
? ((files.size() == 1) && (files.front().type == Type::Photo)) ? ((files.size() == 1) && (files.front().type == Type::Photo))
: ranges::contains(files, Type::Photo, &PreparedFile::type); : ranges::contains(files, Type::Photo, &PreparedFile::type);
@ -174,42 +209,33 @@ std::vector<PreparedGroup> DivideByGroups(
auto group = Ui::PreparedList(); auto group = Ui::PreparedList();
enum class GroupType { using Type = Ui::PreparedFile::Type;
PhotoVideo, auto groupType = AlbumType::None;
File,
Music,
None,
};
// For groupType Type::Video means media album,
// Type::File means file album,
// Type::None means no grouping.
using Type = Ui::PreparedFile::AlbumType;
auto groupType = GroupType::None;
auto result = std::vector<PreparedGroup>(); auto result = std::vector<PreparedGroup>();
auto pushGroup = [&] { auto pushGroup = [&] {
result.push_back(PreparedGroup{ result.push_back(PreparedGroup{
.list = base::take(group), .list = base::take(group),
.grouped = (groupType != GroupType::None) .type = groupType,
}); });
}; };
for (auto i = 0; i != list.files.size(); ++i) { for (auto i = 0; i != list.files.size(); ++i) {
auto &file = list.files[i]; auto &file = list.files[i];
const auto fileGroupType = (file.type == Type::Music) const auto fileGroupType = (file.type == Type::Music)
? (groupFiles ? GroupType::Music : GroupType::None) ? (groupFiles ? AlbumType::Music : AlbumType::None)
: (file.type == Type::Video) : (file.type == Type::Video)
? (groupFiles ? GroupType::PhotoVideo : GroupType::None) ? (groupFiles ? AlbumType::PhotoVideo : AlbumType::None)
: (file.type == Type::Photo) : (file.type == Type::Photo)
? ((groupFiles && sendImagesAsPhotos) ? ((groupFiles && sendImagesAsPhotos)
? GroupType::PhotoVideo ? AlbumType::PhotoVideo
: (groupFiles && !sendImagesAsPhotos) : (groupFiles && !sendImagesAsPhotos)
? GroupType::File ? AlbumType::File
: GroupType::None) : AlbumType::None)
: (file.type == Type::File) : (file.type == Type::File)
? (groupFiles ? GroupType::File : GroupType::None) ? (groupFiles ? AlbumType::File : AlbumType::None)
: GroupType::None; : AlbumType::None;
if ((!group.files.empty() && groupType != fileGroupType) if ((!group.files.empty() && groupType != fileGroupType)
|| ((groupType != GroupType::None) || ((groupType != AlbumType::None)
&& (group.files.size() == Ui::MaxAlbumItems()))) { && (group.files.size() == Ui::MaxAlbumItems()))) {
pushGroup(); pushGroup();
} }

View file

@ -36,6 +36,13 @@ struct PreparedFileInformation {
std::variant<v::null_t, Image, Song, Video> media; std::variant<v::null_t, Image, Song, Video> media;
}; };
enum class AlbumType {
None,
PhotoVideo,
Music,
File,
};
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'.
@ -43,12 +50,12 @@ struct PreparedFile {
// Photo-s + Video-s can be grouped if 'groupFiles && sendImagesAsPhotos'. // Photo-s + Video-s can be grouped if 'groupFiles && sendImagesAsPhotos'.
// Video-s can be grouped if 'groupFiles'. // Video-s can be grouped if 'groupFiles'.
// Music-s can be grouped if 'groupFiles'. // Music-s can be grouped if 'groupFiles'.
enum class AlbumType { enum class Type {
File, None,
Photo, Photo,
Video, Video,
Music, Music,
None, File,
}; };
PreparedFile(const QString &path); PreparedFile(const QString &path);
@ -56,15 +63,20 @@ struct PreparedFile {
PreparedFile &operator=(PreparedFile &&other); PreparedFile &operator=(PreparedFile &&other);
~PreparedFile(); ~PreparedFile();
[[nodiscard]] bool canBeInAlbumType(AlbumType album) const;
[[nodiscard]] AlbumType albumType(bool sendImagesAsPhotos) const;
QString path; QString path;
QByteArray content; QByteArray content;
int size = 0; int size = 0;
std::unique_ptr<Ui::PreparedFileInformation> information; std::unique_ptr<Ui::PreparedFileInformation> information;
QImage preview; QImage preview;
QSize shownDimensions; QSize shownDimensions;
AlbumType type = AlbumType::File; Type type = Type::File;
}; };
[[nodiscard]] bool CanBeInAlbumType(PreparedFile::Type type, AlbumType album);
struct PreparedList { struct PreparedList {
enum class Error { enum class Error {
None, None,
@ -104,7 +116,12 @@ struct PreparedList {
struct PreparedGroup { struct PreparedGroup {
PreparedList list; PreparedList list;
bool grouped = false; AlbumType type = AlbumType::None;
[[nodiscard]] bool sentWithCaption() const {
return (list.files.size() == 1)
|| (type == AlbumType::PhotoVideo);
}
}; };
[[nodiscard]] std::vector<PreparedGroup> DivideByGroups( [[nodiscard]] std::vector<PreparedGroup> DivideByGroups(