Allow many previews in SendFilesBox.

This commit is contained in:
John Preston 2020-10-16 10:52:55 +03:00
parent 8d2fa313b7
commit 202534575b
16 changed files with 286 additions and 226 deletions

View file

@ -689,7 +689,7 @@ bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) {
} }
const auto file = &list.files.front(); const auto file = &list.files.front();
if (_isAlbum && (file->type == AlbumType::None)) { if (_isAlbum && (file->type == AlbumType::File)) {
const auto imageAsDoc = [&] { const auto imageAsDoc = [&] {
using Info = Ui::PreparedFileInformation; using Info = Ui::PreparedFileInformation;
const auto fileMedia = &file->information->media; const auto fileMedia = &file->information->media;

View file

@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/input_fields.h" #include "ui/widgets/input_fields.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/wrap/fade_wrap.h" #include "ui/wrap/fade_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/chat/attach/attach_prepare.h" #include "ui/chat/attach/attach_prepare.h"
#include "ui/chat/attach/attach_send_files_way.h" #include "ui/chat/attach/attach_send_files_way.h"
#include "ui/chat/attach/attach_album_preview.h" #include "ui/chat/attach/attach_album_preview.h"
@ -64,12 +65,6 @@ inline bool CanAddUrls(const QList<QUrl> &urls) {
return !urls.isEmpty() && ranges::all_of(urls, &QUrl::isLocalFile); return !urls.isEmpty() && ranges::all_of(urls, &QUrl::isLocalFile);
} }
inline bool IsFirstAlbumItem(const Ui::PreparedList &list) {
using AlbumType = Ui::PreparedFile::AlbumType;
return (list.files.size() > 0)
&& (list.files.front().type != AlbumType::None);
}
inline bool IsSingleItem(const Ui::PreparedList &list) { inline bool IsSingleItem(const Ui::PreparedList &list) {
return list.files.size() == 1; return list.files.size() == 1;
} }
@ -98,9 +93,7 @@ void FileDialogCallback(
rpl::producer<QString> FieldPlaceholder( rpl::producer<QString> FieldPlaceholder(
const Ui::PreparedList &list, const Ui::PreparedList &list,
SendFilesWay way) { SendFilesWay way) {
const auto isAlbum = list.singleAlbumIsPossible return list.canAddCaption(way.groupMediaInAlbums())
&& way.groupMediaInAlbums();
return list.canAddCaption(isAlbum)
? tr::lng_photo_caption() ? tr::lng_photo_caption()
: tr::lng_photos_comment(); : tr::lng_photos_comment();
} }
@ -125,10 +118,14 @@ SendFilesBox::SendFilesBox(
st::confirmCaptionArea, st::confirmCaptionArea,
Ui::InputField::Mode::MultiLine, Ui::InputField::Mode::MultiLine,
nullptr, nullptr,
caption) { caption)
, _scroll(this, st::boxScroll)
, _inner(
_scroll->setOwnedWidget(
object_ptr<Ui::VerticalLayout>(_scroll.data()))) {
} }
void SendFilesBox::initPreview(rpl::producer<int> desiredPreviewHeight) { void SendFilesBox::initPreview() {
using namespace rpl::mappers; using namespace rpl::mappers;
setupControls(); setupControls();
@ -136,8 +133,10 @@ void SendFilesBox::initPreview(rpl::producer<int> desiredPreviewHeight) {
updateBoxSize(); updateBoxSize();
_dimensionsLifetime.destroy(); _dimensionsLifetime.destroy();
_inner->resizeToWidth(st::boxWideWidth);
rpl::combine( rpl::combine(
std::move(desiredPreviewHeight), _inner->heightValue(),
_footerHeight.value(), _footerHeight.value(),
_titleHeight + _1 + _2 _titleHeight + _1 + _2
) | rpl::start_with_next([=](int height) { ) | rpl::start_with_next([=](int height) {
@ -146,102 +145,83 @@ void SendFilesBox::initPreview(rpl::producer<int> desiredPreviewHeight) {
std::min(st::sendMediaPreviewHeightMax, height), std::min(st::sendMediaPreviewHeightMax, height),
true); true);
}, _dimensionsLifetime); }, _dimensionsLifetime);
if (_preview) {
_preview->show();
}
} }
void SendFilesBox::prepareSingleFilePreview() { //void SendFilesBox::prepareSingleFilePreview() {
Expects(IsSingleItem(_list)); // const auto &file = _list.files[0];
// const auto controller = _controller;
// const auto media = Ui::SingleMediaPreview::Create(this, [=] {
// return controller->isGifPausedAtLeastFor(
// Window::GifPauseReason::Layer);
// }, file);
// if (media) {
// _preview = media;
// initPreview(media->desiredHeightValue());
// } else {
// const auto preview = Ui::CreateChild<Ui::SingleFilePreview>(this, file);
// _preview = preview;
// initPreview(preview->desiredHeightValue());
// }
//}
const auto &file = _list.files[0]; //void SendFilesBox::prepareAlbumPreview() {
const auto controller = _controller; // addThumbButtonHandlers(wrap); // #TODO files
const auto media = Ui::SingleMediaPreview::Create(this, [=] { //
return controller->isGifPausedAtLeastFor( // setupShadows(wrap, _albumPreview);
Window::GifPauseReason::Layer); //
}, file); // initPreview(_albumPreview->desiredHeightValue());
if (media) { //
_preview = media; // crl::on_main([=] {
initPreview(media->desiredHeightValue()); // wrap->scrollToY(_lastScrollTop);
} else { // _lastScrollTop = 0;
const auto preview = Ui::CreateChild<Ui::SingleFilePreview>(this, file); // });
_preview = preview; //}
initPreview(preview->desiredHeightValue());
}
}
void SendFilesBox::prepareAlbumPreview() {
const auto wrap = Ui::CreateChild<Ui::ScrollArea>(
this,
st::boxScroll);
_albumPreview = wrap->setOwnedWidget(object_ptr<Ui::AlbumPreview>(
this,
_list,
_sendWay.current()));
addThumbButtonHandlers(wrap);
_preview = wrap;
_albumPreview->show();
setupShadows(wrap, _albumPreview);
initPreview(_albumPreview->desiredHeightValue());
crl::on_main([=] {
wrap->scrollToY(_lastScrollTop);
_lastScrollTop = 0;
});
}
void SendFilesBox::addThumbButtonHandlers(not_null<Ui::ScrollArea*> wrap) { void SendFilesBox::addThumbButtonHandlers(not_null<Ui::ScrollArea*> wrap) {
_albumPreview->thumbDeleted( // #TODO files
) | rpl::start_with_next([=](auto index) { //_albumPreview->thumbDeleted(
_lastScrollTop = wrap->scrollTop(); //) | rpl::start_with_next([=](auto index) {
// _lastScrollTop = wrap->scrollTop();
_list.files.erase(_list.files.begin() + index); // _list.files.erase(_list.files.begin() + index);
applyAlbumOrder(); // applyAlbumOrder();
if (_preview) { // if (_preview) {
_preview->deleteLater(); // _preview->deleteLater();
} // }
_albumPreview = nullptr; // _albumPreview = nullptr;
if (IsSingleItem(_list)) { // refreshAllAfterAlbumChanges();
_list.singleAlbumIsPossible = false; //}, _albumPreview->lifetime());
}
refreshAllAfterAlbumChanges(); //_albumPreview->thumbChanged(
}, _albumPreview->lifetime()); //) | rpl::start_with_next([=](auto index) {
// _lastScrollTop = wrap->scrollTop();
_albumPreview->thumbChanged( // const auto callback = [=](FileDialog::OpenResult &&result) {
) | rpl::start_with_next([=](auto index) { // FileDialogCallback(
_lastScrollTop = wrap->scrollTop(); // std::move(result),
// true,
// [=] (auto list) {
// _list.files[index] = std::move(list.files.front());
// applyAlbumOrder();
const auto callback = [=](FileDialog::OpenResult &&result) { // if (_preview) {
FileDialogCallback( // _preview->deleteLater();
std::move(result), // }
true, // _albumPreview = nullptr;
[=] (auto list) {
_list.files[index] = std::move(list.files.front());
applyAlbumOrder();
if (_preview) { // refreshAllAfterAlbumChanges();
_preview->deleteLater(); // });
} // };
_albumPreview = nullptr;
refreshAllAfterAlbumChanges(); // FileDialog::GetOpenPath(
}); // this,
}; // tr::lng_choose_file(tr::now),
// FileDialog::AlbumFilesFilter(),
// crl::guard(this, callback));
FileDialog::GetOpenPath( //}, _albumPreview->lifetime());
this,
tr::lng_choose_file(tr::now),
FileDialog::AlbumFilesFilter(),
crl::guard(this, callback));
}, _albumPreview->lifetime());
} }
void SendFilesBox::setupShadows( void SendFilesBox::setupShadows(
@ -288,6 +268,10 @@ void SendFilesBox::prepare() {
setupCaption(); setupCaption();
setupSendWayControls(); setupSendWayControls();
preparePreview(); preparePreview();
initPreview();
_scroll->show();
_inner->show();
boxClosing() | rpl::start_with_next([=] { boxClosing() | rpl::start_with_next([=] {
if (!_confirmed && _cancelledCallback) { if (!_confirmed && _cancelledCallback) {
@ -379,10 +363,6 @@ void SendFilesBox::initSendWay() {
_sendWay.changes( _sendWay.changes(
) | rpl::start_with_next([=](SendFilesWay value) { ) | rpl::start_with_next([=](SendFilesWay value) {
updateCaptionPlaceholder(); updateCaptionPlaceholder();
applyAlbumOrder();
if (_albumPreview) {
_albumPreview->setSendWay(value);
}
updateEmojiPanelGeometry(); updateEmojiPanelGeometry();
setInnerFocus(); setInnerFocus();
}, lifetime()); }, lifetime());
@ -393,9 +373,8 @@ void SendFilesBox::updateCaptionPlaceholder() {
return; return;
} }
const auto sendWay = _sendWay.current(); const auto sendWay = _sendWay.current();
const auto isAlbum = _list.singleAlbumIsPossible if (!_list.canAddCaption(sendWay.groupMediaInAlbums())
&& sendWay.groupMediaInAlbums(); && _sendLimit == SendLimit::One) {
if (!_list.canAddCaption(isAlbum) && _sendLimit == SendLimit::One) {
_caption->hide(); _caption->hide();
if (_emojiToggle) { if (_emojiToggle) {
_emojiToggle->hide(); _emojiToggle->hide();
@ -410,11 +389,73 @@ void SendFilesBox::updateCaptionPlaceholder() {
} }
void SendFilesBox::preparePreview() { void SendFilesBox::preparePreview() {
if (IsSingleItem(_list)) { using Type = Ui::PreparedFile::AlbumType;
prepareSingleFilePreview();
} else { _blocks.clear();
prepareAlbumPreview(); // #TODO files many albums auto albumStart = -1;
const auto finishAlbum = [&](int till) {
if (albumStart < 0) {
return;
} }
const auto count = (till - albumStart);
const auto preview = _inner->add(object_ptr<Ui::AlbumPreview>(
this,
gsl::make_span(_list.files).subspan(albumStart, count),
_sendWay.current()));
auto &block = _blocks.emplace_back();
block.fromIndex = albumStart;
block.tillIndex = albumStart + count;
block.preview.reset(preview);
block.preview->show();
_sendWay.changes(
) | rpl::start_with_next([=](SendFilesWay value) {
applyAlbumOrder(preview, albumStart);
preview->setSendWay(value);
}, preview->lifetime());
albumStart = -1;
};
const auto finishSingle = [&](int index) {
const auto &file = _list.files[index];
const auto controller = _controller;
auto &block = _blocks.emplace_back();
block.fromIndex = index;
block.tillIndex = index + 1;
const auto media = Ui::SingleMediaPreview::Create(this, [=] {
return controller->isGifPausedAtLeastFor(
Window::GifPauseReason::Layer);
}, file);
if (media) {
block.preview.reset(
_inner->add(object_ptr<Ui::SingleMediaPreview>::fromRaw(
media)));
} else {
block.preview.reset(
_inner->add(object_ptr<Ui::SingleFilePreview>(this, file)));
}
block.preview->show();
};
for (auto i = 0, count = int(_list.files.size()); i != count; ++i) {
const auto type = _list.files[i].type;
if (albumStart >= 0) {
const auto albumCount = (i - albumStart);
if (type == Type::File || (albumCount == Ui::MaxAlbumItems())) {
finishAlbum(i);
} else {
continue;
}
}
if (type != Type::File) {
if (albumStart < 0) {
albumStart = i;
}
continue;
}
finishSingle(i);
}
finishAlbum(_list.files.size());
} }
void SendFilesBox::setupControls() { void SendFilesBox::setupControls() {
@ -479,12 +520,10 @@ void SendFilesBox::updateSendWayControlsVisibility() {
_groupFiles->setVisible(!onlyOne); _groupFiles->setVisible(!onlyOne);
} }
void SendFilesBox::applyAlbumOrder() { void SendFilesBox::applyAlbumOrder(
if (!_albumPreview) { not_null<Ui::AlbumPreview*> preview,
return; int from) {
} const auto order = preview->takeOrder();
const auto order = _albumPreview->takeOrder();
const auto isDefault = [&] { const auto isDefault = [&] {
for (auto i = 0, count = int(order.size()); i != count; ++i) { for (auto i = 0, count = int(order.size()); i != count; ++i) {
if (order[i] != i) { if (order[i] != i) {
@ -497,7 +536,14 @@ void SendFilesBox::applyAlbumOrder() {
return; return;
} }
_list = Ui::PreparedList::Reordered(std::move(_list), order); auto elements = std::vector<Ui::PreparedFile>();
elements.reserve(order.size());
for (const auto index : order) {
elements.push_back(std::move(_list.files[from + index]));
}
for (auto i = 0, count = int(order.size()); i != count; ++i) {
_list.files[from + i] = std::move(elements[i]);
}
} }
void SendFilesBox::setupCaption() { void SendFilesBox::setupCaption() {
@ -604,20 +650,21 @@ void SendFilesBox::captionResized() {
} }
bool SendFilesBox::canAddFiles(not_null<const QMimeData*> data) const { bool SendFilesBox::canAddFiles(not_null<const QMimeData*> data) const {
const auto urls = data->hasUrls() ? data->urls() : QList<QUrl>(); return (data->hasUrls() && CanAddUrls(data->urls())) || data->hasImage();
auto filesCount = CanAddUrls(urls) ? urls.size() : 0; //const auto urls = data->hasUrls() ? data->urls() : QList<QUrl>();
if (!filesCount && data->hasImage()) { //auto filesCount = CanAddUrls(urls) ? urls.size() : 0;
++filesCount; //if (!filesCount && data->hasImage()) {
} // ++filesCount;
//}
if (_list.files.size() + filesCount > Ui::MaxAlbumItems()) { //if (_list.files.size() + filesCount > Ui::MaxAlbumItems()) { // #TODO files
return false; // return false;
} else if (_list.files.size() > 1 && !_albumPreview) { //} else if (_list.files.size() > 1 && !_albumPreview) {
return false; // return false;
} else if (!IsFirstAlbumItem(_list)) { //} else if (!IsFirstAlbumItem(_list)) {
return false; // return false;
} //}
return true; //return true;
} }
bool SendFilesBox::addFiles(not_null<const QMimeData*> data) { bool SendFilesBox::addFiles(not_null<const QMimeData*> data) {
@ -661,10 +708,10 @@ bool SendFilesBox::addFiles(Ui::PreparedList list) {
//} else if (!IsFirstAlbumItem(_list)) { //} else if (!IsFirstAlbumItem(_list)) {
// return false; // return false;
} }
applyAlbumOrder(); //applyAlbumOrder();
delete base::take(_preview); //delete base::take(_preview);
_albumPreview = nullptr; //_albumPreview = nullptr;
return false;
_list.mergeToEnd(std::move(list), cutToAlbumSize); _list.mergeToEnd(std::move(list), cutToAlbumSize);
refreshAllAfterAlbumChanges(); refreshAllAfterAlbumChanges();
@ -769,10 +816,8 @@ void SendFilesBox::updateControlsGeometry() {
bottom -= st::boxPhotoCompressedSkip + pointer->heightNoMargins(); bottom -= st::boxPhotoCompressedSkip + pointer->heightNoMargins();
} }
} }
if (_preview) { _scroll->resize(width(), bottom - _titleHeight);
_preview->resize(width(), bottom - _titleHeight); _scroll->move(0, _titleHeight);
_preview->move(0, _titleHeight);
}
} }
void SendFilesBox::setInnerFocus() { void SendFilesBox::setInnerFocus() {
@ -809,7 +854,7 @@ void SendFilesBox::send(
Core::App().saveSettingsDelayed(); Core::App().saveSettingsDelayed();
} }
applyAlbumOrder(); //applyAlbumOrder(); // #TODO files
_confirmed = true; _confirmed = true;
if (_confirmedCallback) { if (_confirmedCallback) {
auto caption = (_caption && !_caption->isHidden()) auto caption = (_caption && !_caption->isHidden())

View file

@ -34,6 +34,7 @@ class InputField;
struct GroupMediaLayout; struct GroupMediaLayout;
class EmojiButton; class EmojiButton;
class AlbumPreview; class AlbumPreview;
class VerticalLayout;
} // namespace Ui } // namespace Ui
namespace Window { namespace Window {
@ -83,8 +84,13 @@ protected:
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
private: private:
struct Block {
base::unique_qptr<Ui::RpWidget> preview;
int fromIndex = 0;
int tillIndex = 0;
};
void initSendWay(); void initSendWay();
void initPreview(rpl::producer<int> desiredPreviewHeight); void initPreview();
void setupControls(); void setupControls();
void setupSendWayControls(); void setupSendWayControls();
@ -99,9 +105,7 @@ private:
void emojiFilterForGeometry(not_null<QEvent*> event); void emojiFilterForGeometry(not_null<QEvent*> event);
void preparePreview(); void preparePreview();
void prepareSingleFilePreview(); void applyAlbumOrder(not_null<Ui::AlbumPreview*> preview, int from);
void prepareAlbumPreview();
void applyAlbumOrder();
void send(Api::SendOptions options, bool ctrlShiftEnter = false); void send(Api::SendOptions options, bool ctrlShiftEnter = false);
void sendSilent(); void sendSilent();
@ -157,8 +161,9 @@ private:
rpl::event_stream<> _albumChanged; rpl::event_stream<> _albumChanged;
rpl::lifetime _dimensionsLifetime; rpl::lifetime _dimensionsLifetime;
QWidget *_preview = nullptr; object_ptr<Ui::ScrollArea> _scroll;
Ui::AlbumPreview *_albumPreview = nullptr; QPointer<Ui::VerticalLayout> _inner;
std::vector<Block> _blocks;
int _lastScrollTop = 0; int _lastScrollTop = 0;

View file

@ -4097,9 +4097,7 @@ bool HistoryWidget::showSendingFilesError(
} else if (!canWriteMessage()) { } else if (!canWriteMessage()) {
return tr::lng_forward_send_files_cant(tr::now); return tr::lng_forward_send_files_cant(tr::now);
} }
if (list.files.size() > 1 if (_peer->slowmodeApplied() && !list.canBeSentInSlowmode()) {
&& _peer->slowmodeApplied()
&& !list.singleAlbumIsPossible) {
return tr::lng_slowmode_no_many(tr::now); return tr::lng_slowmode_no_many(tr::now);
} else if (const auto left = _peer->slowmodeSecondsLeft()) { } else if (const auto left = _peer->slowmodeSecondsLeft()) {
return tr::lng_slowmode_enabled( return tr::lng_slowmode_enabled(

View file

@ -800,15 +800,14 @@ void RepliesWidget::uploadFile(
bool RepliesWidget::showSendingFilesError( bool RepliesWidget::showSendingFilesError(
const Ui::PreparedList &list) const { const Ui::PreparedList &list) const {
const auto text = [&] { const auto text = [&] {
const auto peer = _history->peer;
const auto error = Data::RestrictionError( const auto error = Data::RestrictionError(
_history->peer, peer,
ChatRestriction::f_send_media); ChatRestriction::f_send_media);
if (error) { if (error) {
return *error; return *error;
} }
if (list.files.size() > 1 if (peer->slowmodeApplied() && !list.canBeSentInSlowmode()) {
&& _history->peer->slowmodeApplied()
&& !list.singleAlbumIsPossible) {
return tr::lng_slowmode_no_many(tr::now); return tr::lng_slowmode_no_many(tr::now);
} else if (const auto left = _history->peer->slowmodeSecondsLeft()) { } else if (const auto left = _history->peer->slowmodeSecondsLeft()) {
return tr::lng_slowmode_enabled( return tr::lng_slowmode_enabled(

View file

@ -530,10 +530,11 @@ FileLoadTask::FileLoadTask(
FileLoadTask::~FileLoadTask() = default; FileLoadTask::~FileLoadTask() = default;
std::unique_ptr<Ui::PreparedFileInformation> FileLoadTask::ReadMediaInformation( auto FileLoadTask::ReadMediaInformation(
const QString &filepath, const QString &filepath,
const QByteArray &content, const QByteArray &content,
const QString &filemime) { const QString &filemime)
-> std::unique_ptr<Ui::PreparedFileInformation> {
auto result = std::make_unique<Ui::PreparedFileInformation>(); auto result = std::make_unique<Ui::PreparedFileInformation>();
result->filemime = filemime; result->filemime = filemime;

View file

@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_common.h" #include "api/api_common.h"
#include "ui/chat/attach/attach_prepare.h" #include "ui/chat/attach/attach_prepare.h"
constexpr auto kFileSizeLimit = 2000 * 1024 * 1024; // Load files up to 1500mb constexpr auto kFileSizeLimit = 2000 * 1024 * 1024; // Load files up to 2000MB
enum class SendMediaType { enum class SendMediaType {
Photo, Photo,

View file

@ -62,11 +62,10 @@ QSize PrepareShownDimensions(const QImage &preview) {
: result; : result;
} }
bool PrepareAlbumMediaIsWaiting( bool PrepareDetailsIsWaiting(
QSemaphore &semaphore, QSemaphore &semaphore,
PreparedFile &file, PreparedFile &file,
int previewWidth) { int previewWidth) {
// TODO: Use some special thread queue, like a separate QThreadPool.
crl::async([=, &semaphore, &file] { crl::async([=, &semaphore, &file] {
const auto guard = gsl::finally([&] { semaphore.release(); }); const auto guard = gsl::finally([&] { semaphore.release(); });
if (!file.path.isEmpty()) { if (!file.path.isEmpty()) {
@ -116,29 +115,21 @@ bool PrepareAlbumMediaIsWaiting(
return true; return true;
} }
void PrepareAlbum(PreparedList &result, int previewWidth) { void PrepareDetailsInParallel(PreparedList &result, int previewWidth) {
const auto count = int(result.files.size()); Expects(result.files.size() <= Ui::MaxAlbumItems());
if (count > Ui::MaxAlbumItems()) {
return;
}
//result.albumIsPossible = (count > 1);
auto waiting = 0; auto waiting = 0;
QSemaphore semaphore; QSemaphore semaphore;
for (auto &file : result.files) { for (auto &file : result.files) {
if (PrepareAlbumMediaIsWaiting(semaphore, file, previewWidth)) { if (PrepareDetailsIsWaiting(
semaphore,
file,
previewWidth)) {
++waiting; ++waiting;
} }
} }
if (waiting > 0) { if (waiting > 0) {
semaphore.acquire(waiting); semaphore.acquire(waiting);
//if (result.albumIsPossible) {
// const auto badIt = ranges::find(
// result.files,
// PreparedFile::AlbumType::None,
// [](const PreparedFile &file) { return file.type; });
// result.albumIsPossible = (badIt == result.files.end());
//}
} }
} }
@ -250,13 +241,15 @@ PreparedList PrepareMediaList(const QStringList &files, int previewWidth) {
file file
}; };
} }
const auto toCompress = HasExtensionFrom(file, extensionsToCompress); if (result.files.size() < Ui::MaxAlbumItems()) {
if (filesize > App::kImageSizeLimit || !toCompress) {
// result.allFilesForCompress = false;
}
result.files.emplace_back(file); result.files.emplace_back(file);
result.files.back().size = filesize;
} else {
result.filesToProcess.emplace_back(file);
result.files.back().size = filesize;
} }
PrepareAlbum(result, previewWidth); }
PrepareDetailsInParallel(result, previewWidth);
return result; return result;
} }
@ -276,7 +269,7 @@ PreparedList PrepareMediaFromImage(
file.information); file.information);
} }
result.files.push_back(std::move(file)); result.files.push_back(std::move(file));
PrepareAlbum(result, previewWidth); PrepareDetailsInParallel(result, previewWidth);
return result; return result;
} }
@ -304,7 +297,7 @@ std::optional<PreparedList> PreparedFileFromFilesDialog(
if (isAlbum) { if (isAlbum) {
const auto file = &list.files.front(); const auto file = &list.files.front();
if (!Core::IsMimeAcceptedForAlbum(mimeFile) if (!Core::IsMimeAcceptedForAlbum(mimeFile)
|| file->type == Storage::PreparedFile::AlbumType::None) { || file->type == Storage::PreparedFile::AlbumType::File) {
errorCallback(tr::lng_edit_media_album_error); errorCallback(tr::lng_edit_media_album_error);
return std::nullopt; return std::nullopt;
} }
@ -361,7 +354,6 @@ std::optional<PreparedList> PreparedFileFromFilesDialog(
} }
auto list = PreparedList(temp.error, temp.errorData); auto list = PreparedList(temp.error, temp.errorData);
//list.albumIsPossible = isAlbum;
list.files = std::move(filteredFiles); list.files = std::move(filteredFiles);
return list; return list;

View file

@ -22,7 +22,7 @@ constexpr auto kDragDuration = crl::time(200);
AlbumPreview::AlbumPreview( AlbumPreview::AlbumPreview(
QWidget *parent, QWidget *parent,
const PreparedList &list, gsl::span<PreparedFile> list,
SendFilesWay way) SendFilesWay way)
: RpWidget(parent) : RpWidget(parent)
, _list(list) , _list(list)
@ -69,7 +69,7 @@ auto AlbumPreview::generateOrderedLayout() const
auto sizes = ranges::view::all( auto sizes = ranges::view::all(
_order _order
) | ranges::view::transform([&](int index) { ) | ranges::view::transform([&](int index) {
return _list.files[index].shownDimensions; return _list[index].shownDimensions;
}) | ranges::to_vector; }) | ranges::to_vector;
auto layout = LayoutMediaGroup( auto layout = LayoutMediaGroup(
@ -82,19 +82,19 @@ auto AlbumPreview::generateOrderedLayout() const
} }
std::vector<int> AlbumPreview::defaultOrder() const { std::vector<int> AlbumPreview::defaultOrder() const {
const auto count = int(_list.files.size()); const auto count = int(_list.size());
return ranges::view::ints(0, count) | ranges::to_vector; return ranges::view::ints(0, count) | ranges::to_vector;
} }
void AlbumPreview::prepareThumbs() { void AlbumPreview::prepareThumbs() {
_order = defaultOrder(); _order = defaultOrder();
const auto count = int(_list.files.size()); const auto count = int(_list.size());
const auto layout = generateOrderedLayout(); const auto layout = generateOrderedLayout();
_thumbs.reserve(count); _thumbs.reserve(count);
for (auto i = 0; i != count; ++i) { for (auto i = 0; i != count; ++i) {
_thumbs.push_back(std::make_unique<AlbumThumbnail>( _thumbs.push_back(std::make_unique<AlbumThumbnail>(
_list.files[i], _list[i],
layout[i], layout[i],
this, this,
[=] { changeThumbByIndex(thumbIndex(thumbUnderCursor())); }, [=] { changeThumbByIndex(thumbIndex(thumbUnderCursor())); },

View file

@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui { namespace Ui {
struct PreparedList; struct PreparedFile;
struct GroupMediaLayout; struct GroupMediaLayout;
class AlbumThumbnail; class AlbumThumbnail;
@ -20,18 +20,18 @@ class AlbumPreview final : public RpWidget {
public: public:
AlbumPreview( AlbumPreview(
QWidget *parent, QWidget *parent,
const PreparedList &list, gsl::span<PreparedFile> list,
SendFilesWay way); SendFilesWay way);
~AlbumPreview(); ~AlbumPreview();
void setSendWay(SendFilesWay way); void setSendWay(SendFilesWay way);
std::vector<int> takeOrder(); std::vector<int> takeOrder();
auto thumbDeleted() { [[nodiscard]] rpl::producer<int> thumbDeleted() const {
return _thumbDeleted.events(); return _thumbDeleted.events();
} }
auto thumbChanged() { [[nodiscard]] rpl::producer<int> thumbChanged() const {
return _thumbChanged.events(); return _thumbChanged.events();
} }
@ -73,7 +73,7 @@ private:
void cancelDrag(); void cancelDrag();
void finishDrag(); void finishDrag();
const PreparedList &_list; gsl::span<PreparedFile> _list;
SendFilesWay _sendWay; SendFilesWay _sendWay;
style::cursor _cursor = style::cur_default; style::cursor _cursor = style::cur_default;
std::vector<int> _order; std::vector<int> _order;

View file

@ -32,7 +32,6 @@ PreparedList PreparedList::Reordered(
Expects(list.files.size() == order.size()); Expects(list.files.size() == order.size());
auto result = PreparedList(list.error, list.errorData); auto result = PreparedList(list.error, list.errorData);
result.singleAlbumIsPossible = list.singleAlbumIsPossible;
result.files.reserve(list.files.size()); result.files.reserve(list.files.size());
for (auto index : order) { for (auto index : order) {
result.files.push_back(std::move(list.files[index])); result.files.push_back(std::move(list.files[index]));
@ -58,28 +57,50 @@ void PreparedList::mergeToEnd(PreparedList &&other, bool cutToAlbumSize) {
} }
files.push_back(std::move(file)); files.push_back(std::move(file));
} }
if (files.size() > 1 && files.size() <= kMaxAlbumCount) {
const auto badIt = ranges::find(
files,
PreparedFile::AlbumType::None,
[](const PreparedFile &file) { return file.type; });
singleAlbumIsPossible = (badIt == files.end());
} else {
singleAlbumIsPossible = false;
}
} }
bool PreparedList::canAddCaption(bool isAlbum) const { bool PreparedList::canBeSentInSlowmode() const {
const auto isSticker = [&] { if (!filesToProcess.empty()) {
if (files.empty()) { return false;
} else if (files.size() < 2) {
return true;
} else if (files.size() > kMaxAlbumCount) {
return false; return false;
} }
return Core::IsMimeSticker(files.front().mime)
const auto hasFiles = ranges::contains(
files,
PreparedFile::AlbumType::File,
&PreparedFile::type);
const auto hasVideos = ranges::contains(
files,
PreparedFile::AlbumType::Video,
&PreparedFile::type);
// File-s and Video-s never can be grouped.
return !hasFiles || !hasVideos;
}
bool PreparedList::canAddCaption(bool groupMediaInAlbums) const {
if (!filesToProcess.empty()
|| files.empty()
|| files.size() > kMaxAlbumCount) {
return false;
}
if (files.size() == 1) {
const auto isSticker = Core::IsMimeSticker(files.front().mime)
|| files.front().path.endsWith( || files.front().path.endsWith(
qstr(".tgs"), qstr(".tgs"),
Qt::CaseInsensitive); Qt::CaseInsensitive);
}; return !isSticker;
return isAlbum || (files.size() == 1 && !isSticker()); } else if (!groupMediaInAlbums) {
return false;
}
const auto hasFiles = ranges::contains(
files,
PreparedFile::AlbumType::File,
&PreparedFile::type);
return !hasFiles;
} }
int MaxAlbumItems() { int MaxAlbumItems() {

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include <QtCore/QSemaphore>
#include <deque> #include <deque>
namespace Ui { namespace Ui {
@ -34,8 +35,15 @@ struct PreparedFileInformation {
}; };
struct PreparedFile { struct PreparedFile {
// File-s can be grouped if 'groupFiles'.
// File-s + Photo-s can be grouped if 'groupFiles && !sendImagesAsPhotos'.
// Photo-s can be grouped if '(groupFiles && !sendImagesAsPhotos)
// || (groupMediaInAlbums && sendImagesAsPhotos)'.
// Photo-s + Video-s can be grouped if 'groupMediaInAlbums
// && sendImagesAsPhotos'.
// Video-s can be grouped if 'groupMediaInAlbums'.
enum class AlbumType { enum class AlbumType {
None, File,
Photo, Photo,
Video, Video,
}; };
@ -48,10 +56,11 @@ struct PreparedFile {
QString path; QString path;
QByteArray content; QByteArray content;
QString mime; QString mime;
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::None; AlbumType type = AlbumType::File;
}; };
struct PreparedList { struct PreparedList {
@ -73,16 +82,14 @@ struct PreparedList {
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 isAlbum) const; [[nodiscard]] bool canAddCaption(bool groupMediaInAlbums) const;
[[nodiscard]] bool canBeSentInSlowmode() const;
Error error = Error::None; Error error = Error::None;
QString errorData; QString errorData;
std::vector<PreparedFile> files; std::vector<PreparedFile> files;
std::deque<PreparedFile> filesToProcess; std::deque<PreparedFile> filesToProcess;
std::optional<bool> overrideSendImagesAsPhotos; std::optional<bool> overrideSendImagesAsPhotos;
//bool someFilesForCompress = false;
//bool someAlbumIsPossible = false;
bool singleAlbumIsPossible = false;
}; };
[[nodiscard]] int MaxAlbumItems(); [[nodiscard]] int MaxAlbumItems();

View file

@ -25,6 +25,11 @@ SingleFilePreview::SingleFilePreview(
const PreparedFile &file) const PreparedFile &file)
: RpWidget(parent) { : RpWidget(parent) {
preparePreview(file); preparePreview(file);
auto h = _fileThumb.isNull()
? (st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom())
: (st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom());
resize(width(), st::boxPhotoPadding.top() + h + st::msgShadow);
} }
void SingleFilePreview::prepareThumb(const QImage &preview) { void SingleFilePreview::prepareThumb(const QImage &preview) {
@ -163,11 +168,4 @@ void SingleFilePreview::paintEvent(QPaintEvent *e) {
p.drawTextLeft(x + nameleft, y + statustop, width(), _statusText); p.drawTextLeft(x + nameleft, y + statustop, width(), _statusText);
} }
rpl::producer<int> SingleFilePreview::desiredHeightValue() const {
auto h = _fileThumb.isNull()
? (st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom())
: (st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom());
return rpl::single(st::boxPhotoPadding.top() + h + st::msgShadow);
}
} // namespace Ui } // namespace Ui

View file

@ -19,8 +19,6 @@ public:
QWidget *parent, QWidget *parent,
const PreparedFile &file); const PreparedFile &file);
rpl::producer<int> desiredHeightValue() const override;
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;

View file

@ -135,6 +135,8 @@ void SingleMediaPreview::preparePreview(
_preview.setDevicePixelRatio(style::DevicePixelRatio()); _preview.setDevicePixelRatio(style::DevicePixelRatio());
prepareAnimatedPreview(animatedPreviewPath); prepareAnimatedPreview(animatedPreviewPath);
resize(width(), st::boxPhotoPadding.top() + _previewHeight);
} }
void SingleMediaPreview::prepareAnimatedPreview( void SingleMediaPreview::prepareAnimatedPreview(
@ -228,8 +230,4 @@ void SingleMediaPreview::paintEvent(QPaintEvent *e) {
} }
} }
rpl::producer<int> SingleMediaPreview::desiredHeightValue() const {
return rpl::single(st::boxPhotoPadding.top() + _previewHeight);
}
} // namespace Ui } // namespace Ui

View file

@ -38,8 +38,6 @@ public:
return _canSendAsPhoto; return _canSendAsPhoto;
} }
rpl::producer<int> desiredHeightValue() const override;
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;