mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Added drag'n'drop area to EditCaptionBox.
This commit is contained in:
parent
6ac9ef34eb
commit
4eaba39a7c
9 changed files with 139 additions and 58 deletions
|
@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_photo_media.h"
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
#include "history/history_drag_area.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
@ -38,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "media/streaming/media_streaming_player.h"
|
#include "media/streaming/media_streaming_player.h"
|
||||||
#include "media/streaming/media_streaming_document.h"
|
#include "media/streaming/media_streaming_document.h"
|
||||||
#include "media/streaming/media_streaming_loader_local.h"
|
#include "media/streaming/media_streaming_loader_local.h"
|
||||||
|
#include "platform/platform_file_utilities.h"
|
||||||
#include "storage/localimageloader.h"
|
#include "storage/localimageloader.h"
|
||||||
#include "storage/storage_media_prepare.h"
|
#include "storage/storage_media_prepare.h"
|
||||||
#include "mtproto/mtproto_config.h"
|
#include "mtproto/mtproto_config.h"
|
||||||
|
@ -64,6 +66,50 @@ namespace {
|
||||||
using namespace ::Media::Streaming;
|
using namespace ::Media::Streaming;
|
||||||
using Data::PhotoSize;
|
using Data::PhotoSize;
|
||||||
|
|
||||||
|
auto ListFromMimeData(not_null<const QMimeData*> data) {
|
||||||
|
using Error = Storage::PreparedList::Error;
|
||||||
|
auto result = data->hasUrls()
|
||||||
|
? Storage::PrepareMediaList(
|
||||||
|
// When we edit media, we need only 1 file.
|
||||||
|
data->urls().mid(0, 1),
|
||||||
|
st::sendMediaPreviewSize)
|
||||||
|
: Storage::PreparedList(Error::EmptyFile, QString());
|
||||||
|
if (result.error == Error::None) {
|
||||||
|
return result;
|
||||||
|
} else if (data->hasImage()) {
|
||||||
|
auto image = Platform::GetImageFromClipboard();
|
||||||
|
if (image.isNull()) {
|
||||||
|
image = qvariant_cast<QImage>(data->imageData());
|
||||||
|
}
|
||||||
|
if (!image.isNull()) {
|
||||||
|
return Storage::PrepareMediaFromImage(
|
||||||
|
std::move(image),
|
||||||
|
QByteArray(),
|
||||||
|
st::sendMediaPreviewSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CheckMimeData(not_null<const QMimeData*> data, bool isAlbum) {
|
||||||
|
if (data->urls().size() > 1) {
|
||||||
|
return false;
|
||||||
|
} else if (data->hasImage()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAlbum && data->hasUrls()) {
|
||||||
|
const auto url = data->urls().front();
|
||||||
|
if (url.isLocalFile()) {
|
||||||
|
using namespace Core;
|
||||||
|
const auto info = QFileInfo(Platform::File::UrlToLocal(url));
|
||||||
|
return IsMimeAcceptedForAlbum(MimeTypeForFile(info).name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
EditCaptionBox::EditCaptionBox(
|
EditCaptionBox::EditCaptionBox(
|
||||||
|
@ -617,12 +663,8 @@ 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 (data->hasImage()) {
|
} else if (CheckMimeData(data, _isAlbum)) {
|
||||||
return true;
|
return true;
|
||||||
} else if (const auto urls = data->urls(); !urls.empty()) {
|
|
||||||
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return data->hasText();
|
return data->hasText();
|
||||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||||
|
@ -640,6 +682,8 @@ void EditCaptionBox::prepare() {
|
||||||
auto cursor = _field->textCursor();
|
auto cursor = _field->textCursor();
|
||||||
cursor.movePosition(QTextCursor::End);
|
cursor.movePosition(QTextCursor::End);
|
||||||
_field->setTextCursor(cursor);
|
_field->setTextCursor(cursor);
|
||||||
|
|
||||||
|
setupDragArea();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) {
|
bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) {
|
||||||
|
@ -647,50 +691,34 @@ bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
using Error = Storage::PreparedList::Error;
|
using Error = Storage::PreparedList::Error;
|
||||||
|
using AlbumType = Storage::PreparedFile::AlbumType;
|
||||||
|
auto list = ListFromMimeData(data);
|
||||||
|
|
||||||
auto list = [&] {
|
|
||||||
auto url = QList<QUrl>();
|
|
||||||
auto canAddUrl = false;
|
|
||||||
// When we edit media, we need only 1 file.
|
|
||||||
if (data->hasUrls()) {
|
|
||||||
const auto first = data->urls().front();
|
|
||||||
url.push_front(first);
|
|
||||||
canAddUrl = first.isLocalFile();
|
|
||||||
}
|
|
||||||
auto result = canAddUrl
|
|
||||||
? Storage::PrepareMediaList(url, st::sendMediaPreviewSize)
|
|
||||||
: Storage::PreparedList(
|
|
||||||
Error::EmptyFile,
|
|
||||||
QString());
|
|
||||||
if (result.error == Error::None) {
|
|
||||||
return result;
|
|
||||||
} else if (data->hasImage()) {
|
|
||||||
auto image = Platform::GetImageFromClipboard();
|
|
||||||
if (image.isNull()) {
|
|
||||||
image = qvariant_cast<QImage>(data->imageData());
|
|
||||||
}
|
|
||||||
if (!image.isNull()) {
|
|
||||||
_isImage = true;
|
|
||||||
_photo = true;
|
|
||||||
return Storage::PrepareMediaFromImage(
|
|
||||||
std::move(image),
|
|
||||||
QByteArray(),
|
|
||||||
st::sendMediaPreviewSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}();
|
|
||||||
if (list.error != Error::None || list.files.empty()) {
|
if (list.error != Error::None || list.files.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (list.files.front().type == Storage::PreparedFile::AlbumType::None
|
|
||||||
&& _isAlbum) {
|
const auto file = &list.files.front();
|
||||||
Ui::show(
|
if (_isAlbum && (file->type == AlbumType::None)) {
|
||||||
Box<InformBox>(tr::lng_edit_media_album_error(tr::now)),
|
const auto imageAsDoc = [&] {
|
||||||
Ui::LayerOption::KeepOther);
|
using Info = FileMediaInformation;
|
||||||
|
const auto fileMedia = &file->information->media;
|
||||||
|
if (const auto image = base::get_if<Info::Image>(fileMedia)) {
|
||||||
|
return !Storage::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);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
_photo = _isImage = (file->type == AlbumType::Photo);
|
||||||
_preparedList = std::move(list);
|
_preparedList = std::move(list);
|
||||||
updateEditPreview();
|
updateEditPreview();
|
||||||
return true;
|
return true;
|
||||||
|
@ -735,6 +763,35 @@ void EditCaptionBox::setupEmojiPanel() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EditCaptionBox::setupDragArea() {
|
||||||
|
auto enterFilter = [=](not_null<const QMimeData*> data) {
|
||||||
|
return !_isAllowedEditMedia ? false : CheckMimeData(data, _isAlbum);
|
||||||
|
};
|
||||||
|
// Avoid both drag areas appearing at one time.
|
||||||
|
auto computeState = [=](const QMimeData *data) {
|
||||||
|
const auto state = Storage::ComputeMimeDataState(data);
|
||||||
|
return (state == Storage::MimeDataState::PhotoFiles)
|
||||||
|
? Storage::MimeDataState::Image
|
||||||
|
: state;
|
||||||
|
};
|
||||||
|
const auto areas = DragArea::SetupDragAreaToContainer(
|
||||||
|
this,
|
||||||
|
std::move(enterFilter),
|
||||||
|
[=](bool f) { _field->setAcceptDrops(f); },
|
||||||
|
nullptr,
|
||||||
|
std::move(computeState));
|
||||||
|
|
||||||
|
const auto droppedCallback = [=](bool compress) {
|
||||||
|
return [=](const QMimeData *data) {
|
||||||
|
fileFromClipboard(data);
|
||||||
|
Window::ActivateWindow(_controller);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
areas.document->setDroppedCallback(droppedCallback(false));
|
||||||
|
areas.photo->setDroppedCallback(droppedCallback(true));
|
||||||
|
}
|
||||||
|
|
||||||
void EditCaptionBox::updateBoxSize() {
|
void EditCaptionBox::updateBoxSize() {
|
||||||
auto newHeight = st::boxPhotoPadding.top() + st::boxPhotoCaptionSkip + _field->height() + errorTopSkip() + st::normalFont->height;
|
auto newHeight = st::boxPhotoPadding.top() + st::boxPhotoCaptionSkip + _field->height() + errorTopSkip() + st::normalFont->height;
|
||||||
if (_photo) {
|
if (_photo) {
|
||||||
|
|
|
@ -79,6 +79,8 @@ private:
|
||||||
void updateEmojiPanelGeometry();
|
void updateEmojiPanelGeometry();
|
||||||
void emojiFilterForGeometry(not_null<QEvent*> event);
|
void emojiFilterForGeometry(not_null<QEvent*> event);
|
||||||
|
|
||||||
|
void setupDragArea();
|
||||||
|
|
||||||
void save();
|
void save();
|
||||||
void captionResized();
|
void captionResized();
|
||||||
|
|
||||||
|
|
|
@ -111,4 +111,11 @@ bool IsMimeSticker(const QString &mime) {
|
||||||
|| IsMimeStickerAnimated(mime);
|
|| IsMimeStickerAnimated(mime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsMimeAcceptedForAlbum(const QString &mime) {
|
||||||
|
return (mime == u"image/jpeg"_q)
|
||||||
|
|| (mime == u"image/png"_q)
|
||||||
|
|| (mime == u"video/mp4"_q)
|
||||||
|
|| (mime == u"video/quicktime"_q);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -41,5 +41,6 @@ MimeType MimeTypeForData(const QByteArray &data);
|
||||||
|
|
||||||
bool IsMimeStickerAnimated(const QString &mime);
|
bool IsMimeStickerAnimated(const QString &mime);
|
||||||
bool IsMimeSticker(const QString &mime);
|
bool IsMimeSticker(const QString &mime);
|
||||||
|
bool IsMimeAcceptedForAlbum(const QString &mime);
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -40,9 +40,10 @@ constexpr auto kDragAreaEvents = {
|
||||||
|
|
||||||
DragArea::Areas DragArea::SetupDragAreaToContainer(
|
DragArea::Areas DragArea::SetupDragAreaToContainer(
|
||||||
not_null<Ui::RpWidget*> container,
|
not_null<Ui::RpWidget*> container,
|
||||||
Fn<bool()> &&dragEnterFilter,
|
Fn<bool(not_null<const QMimeData*>)> &&dragEnterFilter,
|
||||||
Fn<void(bool)> &&setAcceptDropsField,
|
Fn<void(bool)> &&setAcceptDropsField,
|
||||||
Fn<void()> &&updateControlsGeometry) {
|
Fn<void()> &&updateControlsGeometry,
|
||||||
|
DragArea::CallbackComputeState &&computeState) {
|
||||||
|
|
||||||
using DragState = Storage::MimeDataState;
|
using DragState = Storage::MimeDataState;
|
||||||
|
|
||||||
|
@ -161,11 +162,13 @@ DragArea::Areas DragArea::SetupDragAreaToContainer(
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto dragEnterEvent = [=](QDragEnterEvent *e) {
|
const auto dragEnterEvent = [=](QDragEnterEvent *e) {
|
||||||
if (dragEnterFilter && dragEnterFilter()) {
|
if (dragEnterFilter && !dragEnterFilter(e->mimeData())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*attachDragState = Storage::ComputeMimeDataState(e->mimeData());
|
*attachDragState = computeState
|
||||||
|
? computeState(e->mimeData())
|
||||||
|
: Storage::ComputeMimeDataState(e->mimeData());
|
||||||
updateDragAreas();
|
updateDragAreas();
|
||||||
|
|
||||||
if (*attachDragState != DragState::None) {
|
if (*attachDragState != DragState::None) {
|
||||||
|
@ -179,6 +182,10 @@ DragArea::Areas DragArea::SetupDragAreaToContainer(
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto dropEvent = [=](QDropEvent *e) {
|
const auto dropEvent = [=](QDropEvent *e) {
|
||||||
|
// Hide fast to avoid visual bugs in resizable boxes.
|
||||||
|
attachDragDocument->hideFast();
|
||||||
|
attachDragPhoto->hideFast();
|
||||||
|
|
||||||
*attachDragState = DragState::None;
|
*attachDragState = DragState::None;
|
||||||
updateDragAreas();
|
updateDragAreas();
|
||||||
e->acceptProposedAction();
|
e->acceptProposedAction();
|
||||||
|
|
|
@ -10,6 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
enum class MimeDataState;
|
||||||
|
} // namespace Storage
|
||||||
|
|
||||||
class DragArea : public Ui::RpWidget {
|
class DragArea : public Ui::RpWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -20,11 +24,16 @@ public:
|
||||||
DragArea *document;
|
DragArea *document;
|
||||||
DragArea *photo;
|
DragArea *photo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using CallbackComputeState =
|
||||||
|
Fn<Storage::MimeDataState(const QMimeData *data)>;
|
||||||
|
|
||||||
static Areas SetupDragAreaToContainer(
|
static Areas SetupDragAreaToContainer(
|
||||||
not_null<Ui::RpWidget*> container,
|
not_null<Ui::RpWidget*> container,
|
||||||
Fn<bool()> &&dragEnterFilter = nullptr,
|
Fn<bool(not_null<const QMimeData*>)> &&dragEnterFilter = nullptr,
|
||||||
Fn<void(bool)> &&setAcceptDropsField = nullptr,
|
Fn<void(bool)> &&setAcceptDropsField = nullptr,
|
||||||
Fn<void()> &&updateControlsGeometry = nullptr);
|
Fn<void()> &&updateControlsGeometry = nullptr,
|
||||||
|
CallbackComputeState &&computeState = nullptr);
|
||||||
|
|
||||||
void setText(const QString &text, const QString &subtext);
|
void setText(const QString &text, const QString &subtext);
|
||||||
|
|
||||||
|
|
|
@ -449,7 +449,9 @@ HistoryWidget::HistoryWidget(
|
||||||
|
|
||||||
_attachDragAreas = DragArea::SetupDragAreaToContainer(
|
_attachDragAreas = DragArea::SetupDragAreaToContainer(
|
||||||
this,
|
this,
|
||||||
crl::guard(this, [=] { return (!_history || !_canSendMessages); }),
|
crl::guard(this, [=](not_null<const QMimeData*> d) {
|
||||||
|
return _history && _canSendMessages;
|
||||||
|
}),
|
||||||
crl::guard(this, [=](bool f) { _field->setAcceptDrops(f); }),
|
crl::guard(this, [=](bool f) { _field->setAcceptDrops(f); }),
|
||||||
crl::guard(this, [=] { updateControlsGeometry(); }));
|
crl::guard(this, [=] { updateControlsGeometry(); }));
|
||||||
_attachDragAreas.document->setDroppedCallback([=](const QMimeData *data) {
|
_attachDragAreas.document->setDroppedCallback([=](const QMimeData *data) {
|
||||||
|
|
|
@ -1181,7 +1181,7 @@ void ScheduledWidget::clearSelected() {
|
||||||
void ScheduledWidget::setupDragArea() {
|
void ScheduledWidget::setupDragArea() {
|
||||||
const auto areas = DragArea::SetupDragAreaToContainer(
|
const auto areas = DragArea::SetupDragAreaToContainer(
|
||||||
this,
|
this,
|
||||||
[=] { return !_history; },
|
[=](not_null<const QMimeData*> d) { return _history; },
|
||||||
nullptr,
|
nullptr,
|
||||||
[=] { updateControlsGeometry(); });
|
[=] { updateControlsGeometry(); });
|
||||||
|
|
||||||
|
|
|
@ -291,19 +291,15 @@ std::optional<PreparedList> PreparedList::PreparedFileFromFilesDialog(
|
||||||
std::move(result.remoteContent),
|
std::move(result.remoteContent),
|
||||||
previewWidth);
|
previewWidth);
|
||||||
|
|
||||||
if (Core::IsMimeSticker(list.files.front().mime)) {
|
const auto mimeFile = list.files.front().mime;
|
||||||
|
if (Core::IsMimeSticker(mimeFile)) {
|
||||||
errorCallback(tr::lng_edit_media_invalid_file);
|
errorCallback(tr::lng_edit_media_invalid_file);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAlbum) {
|
if (isAlbum) {
|
||||||
const auto albumMimes = {
|
|
||||||
"image/jpeg",
|
|
||||||
"image/png",
|
|
||||||
"video/mp4",
|
|
||||||
};
|
|
||||||
const auto file = &list.files.front();
|
const auto file = &list.files.front();
|
||||||
if (!ranges::contains(albumMimes, file->mime)
|
if (!Core::IsMimeAcceptedForAlbum(mimeFile)
|
||||||
|| file->type == Storage::PreparedFile::AlbumType::None) {
|
|| file->type == Storage::PreparedFile::AlbumType::None) {
|
||||||
errorCallback(tr::lng_edit_media_album_error);
|
errorCallback(tr::lng_edit_media_album_error);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
Loading…
Add table
Reference in a new issue