mirror of https://github.com/procxx/kepka.git
Closed beta 10019010: unified attach button, new intro, new stickers.
Now all files sending is confirmed before preparing for sending. You can paste from clipboard and drag many files at once.
This commit is contained in:
parent
26c08236cd
commit
3cff50009c
Binary file not shown.
Before Width: | Height: | Size: 203 B |
Binary file not shown.
Before Width: | Height: | Size: 337 B |
Binary file not shown.
Before Width: | Height: | Size: 406 B |
Binary file not shown.
Before Width: | Height: | Size: 841 B |
|
@ -829,7 +829,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
"lng_duration_and_size" = "{duration}, {size}";
|
"lng_duration_and_size" = "{duration}, {size}";
|
||||||
"lng_duration_played" = "{played} / {duration}";
|
"lng_duration_played" = "{played} / {duration}";
|
||||||
"lng_date_and_duration" = "{date}, {duration}";
|
"lng_date_and_duration" = "{date}, {duration}";
|
||||||
"lng_choose_images" = "Choose images";
|
"lng_choose_image" = "Choose an image";
|
||||||
|
"lng_choose_files" = "Choose files";
|
||||||
"lng_game_tag" = "Game";
|
"lng_game_tag" = "Game";
|
||||||
|
|
||||||
"lng_context_view_profile" = "View profile";
|
"lng_context_view_profile" = "View profile";
|
||||||
|
@ -876,10 +877,15 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
"lng_really_send_image" = "Do you want to send this image?";
|
"lng_really_send_image" = "Do you want to send this image?";
|
||||||
"lng_really_send_file" = "Do you want to send this file?";
|
"lng_really_send_file" = "Do you want to send this file?";
|
||||||
"lng_really_share_contact" = "Do you want to share this contact?";
|
"lng_really_share_contact" = "Do you want to share this contact?";
|
||||||
"lng_send_image_compressed" = "Send compressed image";
|
"lng_send_images_compress" = "Compressed {count:_not_used_|image|images}";
|
||||||
"lng_send_image_empty" = "Could not send an empty file :(";
|
"lng_send_image_non_local" = "Could not send a non local file: {name}";
|
||||||
"lng_send_image_too_large" = "Could not send a file, because it is larger than 1.5 GB :(";
|
"lng_send_image_empty" = "Could not send an empty file: {name}";
|
||||||
|
"lng_send_image_too_large" = "Could not send a file, because it is larger than 1500 MB: {name}";
|
||||||
"lng_send_folder" = "Could not send «{name}» because it is a directory :(";
|
"lng_send_folder" = "Could not send «{name}» because it is a directory :(";
|
||||||
|
"lng_send_images_selected" = "{count:_not_used_|# image|# images} selected";
|
||||||
|
"lng_send_photos" = "Send {count:_not_used_|# photo|# photos}";
|
||||||
|
"lng_send_files_selected" = "{count:_not_used_|# file|# files} selected";
|
||||||
|
"lng_send_files" = "Send {count:_not_used_|# file|# files}";
|
||||||
|
|
||||||
"lng_forward_choose" = "Choose recipient...";
|
"lng_forward_choose" = "Choose recipient...";
|
||||||
"lng_forward_cant" = "Sorry, no way to forward here :(";
|
"lng_forward_cant" = "Sorry, no way to forward here :(";
|
||||||
|
|
|
@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 0,10,19,9
|
FILEVERSION 0,10,19,10
|
||||||
PRODUCTVERSION 0,10,19,9
|
PRODUCTVERSION 0,10,19,10
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -51,10 +51,10 @@ BEGIN
|
||||||
BLOCK "040904b0"
|
BLOCK "040904b0"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||||
VALUE "FileVersion", "0.10.19.9"
|
VALUE "FileVersion", "0.10.19.10"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
||||||
VALUE "ProductName", "Telegram Desktop"
|
VALUE "ProductName", "Telegram Desktop"
|
||||||
VALUE "ProductVersion", "0.10.19.9"
|
VALUE "ProductVersion", "0.10.19.10"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 0,10,19,9
|
FILEVERSION 0,10,19,10
|
||||||
PRODUCTVERSION 0,10,19,9
|
PRODUCTVERSION 0,10,19,10
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -43,10 +43,10 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||||
VALUE "FileDescription", "Telegram Updater"
|
VALUE "FileDescription", "Telegram Updater"
|
||||||
VALUE "FileVersion", "0.10.19.9"
|
VALUE "FileVersion", "0.10.19.10"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
||||||
VALUE "ProductName", "Telegram Desktop"
|
VALUE "ProductName", "Telegram Desktop"
|
||||||
VALUE "ProductVersion", "0.10.19.9"
|
VALUE "ProductVersion", "0.10.19.10"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -2533,20 +2533,15 @@ namespace {
|
||||||
exif_data_free(exifData);
|
exif_data_free(exifData);
|
||||||
}
|
}
|
||||||
#endif // OS_MAC_OLD
|
#endif // OS_MAC_OLD
|
||||||
} else if (opaque && result.hasAlphaChannel()) {
|
} else if (opaque) {
|
||||||
QImage solid(result.width(), result.height(), QImage::Format_ARGB32_Premultiplied);
|
result = Images::prepareOpaque(std_::move(result));
|
||||||
solid.fill(st::imageBgTransparent->c);
|
|
||||||
{
|
|
||||||
QPainter(&solid).drawImage(0, 0, result);
|
|
||||||
}
|
|
||||||
result = solid;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage readImage(const QString &file, QByteArray *format, bool opaque, bool *animated, QByteArray *content) {
|
QImage readImage(const QString &file, QByteArray *format, bool opaque, bool *animated, QByteArray *content) {
|
||||||
QFile f(file);
|
QFile f(file);
|
||||||
if (f.size() > MediaViewImageSizeLimit || !f.open(QIODevice::ReadOnly)) {
|
if (f.size() > kImageSizeLimit || !f.open(QIODevice::ReadOnly)) {
|
||||||
if (animated) *animated = false;
|
if (animated) *animated = false;
|
||||||
return QImage();
|
return QImage();
|
||||||
}
|
}
|
||||||
|
@ -2557,7 +2552,7 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap pixmapFromImageInPlace(QImage &&image) {
|
QPixmap pixmapFromImageInPlace(QImage &&image) {
|
||||||
return QPixmap::fromImage(std_::forward<QImage>(image), Qt::ColorOnly);
|
return QPixmap::fromImage(std_::move(image), Qt::ColorOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
void regPhotoItem(PhotoData *data, HistoryItem *item) {
|
void regPhotoItem(PhotoData *data, HistoryItem *item) {
|
||||||
|
|
|
@ -238,8 +238,10 @@ namespace App {
|
||||||
void setLaunchState(LaunchState state);
|
void setLaunchState(LaunchState state);
|
||||||
void restart();
|
void restart();
|
||||||
|
|
||||||
QImage readImage(QByteArray data, QByteArray *format = 0, bool opaque = true, bool *animated = 0);
|
constexpr auto kFileSizeLimit = 1500 * 1024 * 1024; // Load files up to 1500mb
|
||||||
QImage readImage(const QString &file, QByteArray *format = 0, bool opaque = true, bool *animated = 0, QByteArray *content = 0);
|
constexpr auto kImageSizeLimit = 64 * 1024 * 1024; // Open images up to 64mb jpg/png/gif
|
||||||
|
QImage readImage(QByteArray data, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr);
|
||||||
|
QImage readImage(const QString &file, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr, QByteArray *content = 0);
|
||||||
QPixmap pixmapFromImageInPlace(QImage &&image);
|
QPixmap pixmapFromImageInPlace(QImage &&image);
|
||||||
|
|
||||||
void regPhotoItem(PhotoData *data, HistoryItem *item);
|
void regPhotoItem(PhotoData *data, HistoryItem *item);
|
||||||
|
|
|
@ -1062,7 +1062,7 @@ void AppClass::uploadProfilePhoto(const QImage &tosend, const PeerId &peerId) {
|
||||||
int32 filesize = 0;
|
int32 filesize = 0;
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
|
|
||||||
ReadyLocalMedia ready(PreparePhoto, file, filename, filesize, data, id, id, qsl("jpg"), peerId, photo, photoThumbs, MTP_documentEmpty(MTP_long(0)), jpeg, false, 0);
|
SendMediaReady ready(SendMediaType::Photo, file, filename, filesize, data, id, id, qsl("jpg"), peerId, photo, photoThumbs, MTP_documentEmpty(MTP_long(0)), jpeg, 0);
|
||||||
|
|
||||||
connect(App::uploader(), SIGNAL(photoReady(const FullMsgId&,bool,const MTPInputFile&)), App::app(), SLOT(photoUpdated(const FullMsgId&,bool,const MTPInputFile&)), Qt::UniqueConnection);
|
connect(App::uploader(), SIGNAL(photoReady(const FullMsgId&,bool,const MTPInputFile&)), App::app(), SLOT(photoUpdated(const FullMsgId&,bool,const MTPInputFile&)), Qt::UniqueConnection);
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
#include "platform/platform_file_dialog.h"
|
||||||
|
|
||||||
AboutBox::AboutBox() : AbstractBox(st::aboutWidth, qsl("Telegram Desktop"))
|
AboutBox::AboutBox() : AbstractBox(st::aboutWidth, qsl("Telegram Desktop"))
|
||||||
, _version(this, lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + (cAlphaVersion() ? " alpha" : "") + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), st::aboutVersionLink)
|
, _version(this, lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + (cAlphaVersion() ? " alpha" : "") + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), st::aboutVersionLink)
|
||||||
|
@ -44,8 +45,6 @@ AboutBox::AboutBox() : AbstractBox(st::aboutWidth, qsl("Telegram Desktop"))
|
||||||
connect(_version, SIGNAL(clicked()), this, SLOT(onVersion()));
|
connect(_version, SIGNAL(clicked()), this, SLOT(onVersion()));
|
||||||
connect(_done, SIGNAL(clicked()), this, SLOT(onClose()));
|
connect(_done, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||||
|
|
||||||
prepare();
|
|
||||||
|
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +89,7 @@ void AboutBox::keyPressEvent(QKeyEvent *e) {
|
||||||
QString _getCrashReportFile(const QMimeData *m) {
|
QString _getCrashReportFile(const QMimeData *m) {
|
||||||
if (!m || m->urls().size() != 1 || !m->urls().at(0).isLocalFile()) return QString();
|
if (!m || m->urls().size() != 1 || !m->urls().at(0).isLocalFile()) return QString();
|
||||||
|
|
||||||
auto file = psConvertFileUrl(m->urls().at(0));
|
auto file = Platform::FileDialog::UrlToLocal(m->urls().at(0));
|
||||||
|
|
||||||
return file.endsWith(qstr(".telegramcrash"), Qt::CaseInsensitive) ? file : QString();
|
return file.endsWith(qstr(".telegramcrash"), Qt::CaseInsensitive) ? file : QString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,10 +45,6 @@ void AbstractBox::setAdditionalTitle(const QString &additionalTitle) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractBox::prepare() {
|
|
||||||
raiseShadow();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractBox::keyPressEvent(QKeyEvent *e) {
|
void AbstractBox::keyPressEvent(QKeyEvent *e) {
|
||||||
if (e->key() == Qt::Key_Escape) {
|
if (e->key() == Qt::Key_Escape) {
|
||||||
onClose();
|
onClose();
|
||||||
|
|
|
@ -39,7 +39,6 @@ public:
|
||||||
void setTitleText(const QString &title);
|
void setTitleText(const QString &title);
|
||||||
void setAdditionalTitle(const QString &additionalTitle);
|
void setAdditionalTitle(const QString &additionalTitle);
|
||||||
void setBlockTitle(bool block, bool withClose = true, bool withShadow = true);
|
void setBlockTitle(bool block, bool withClose = true, bool withShadow = true);
|
||||||
void raiseShadow();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onClose();
|
void onClose();
|
||||||
|
@ -49,7 +48,7 @@ protected:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
void prepare();
|
void raiseShadow();
|
||||||
int titleHeight() const;
|
int titleHeight() const;
|
||||||
void paintTitle(Painter &p, const QString &title, const QString &additional = QString());
|
void paintTitle(Painter &p, const QString &title, const QString &additional = QString());
|
||||||
void setMaxHeight(int32 maxHeight);
|
void setMaxHeight(int32 maxHeight);
|
||||||
|
|
|
@ -87,8 +87,6 @@ void AddContactBox::initBox() {
|
||||||
connect(_first, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
connect(_first, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||||
connect(_last, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
connect(_last, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||||
connect(_phone, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
connect(_phone, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddContactBox::doSetInnerFocus() {
|
void AddContactBox::doSetInnerFocus() {
|
||||||
|
@ -279,13 +277,11 @@ GroupInfoBox::GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose) : Ab
|
||||||
_photo->setClickedCallback([this] {
|
_photo->setClickedCallback([this] {
|
||||||
auto imgExtensions = cImgExtensions();
|
auto imgExtensions = cImgExtensions();
|
||||||
auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter();
|
auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter();
|
||||||
_setPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_images), filter);
|
_setPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_image), filter);
|
||||||
});
|
});
|
||||||
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
|
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
|
||||||
notifyFileQueryUpdated(update);
|
notifyFileQueryUpdated(update);
|
||||||
});
|
});
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupInfoBox::doSetInnerFocus() {
|
void GroupInfoBox::doSetInnerFocus() {
|
||||||
|
@ -459,8 +455,6 @@ SetupChannelBox::SetupChannelBox(ChannelData *channel, bool existing) : Abstract
|
||||||
|
|
||||||
connect(_public, SIGNAL(changed()), this, SLOT(onPrivacyChange()));
|
connect(_public, SIGNAL(changed()), this, SLOT(onPrivacyChange()));
|
||||||
connect(_private, SIGNAL(changed()), this, SLOT(onPrivacyChange()));
|
connect(_private, SIGNAL(changed()), this, SLOT(onPrivacyChange()));
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupChannelBox::doSetInnerFocus() {
|
void SetupChannelBox::doSetInnerFocus() {
|
||||||
|
@ -673,12 +667,11 @@ void SetupChannelBox::onPrivacyChange() {
|
||||||
if (_public->checked()) {
|
if (_public->checked()) {
|
||||||
if (_tooMuchUsernames) {
|
if (_tooMuchUsernames) {
|
||||||
_private->setChecked(true);
|
_private->setChecked(true);
|
||||||
Ui::showLayer(new RevokePublicLinkBox([this, weak_this = weakThis()]() {
|
Ui::showLayer(new RevokePublicLinkBox(base::lambda_guarded(this, [this] {
|
||||||
if (!weak_this) return;
|
|
||||||
_tooMuchUsernames = false;
|
_tooMuchUsernames = false;
|
||||||
_public->setChecked(true);
|
_public->setChecked(true);
|
||||||
onCheck();
|
onCheck();
|
||||||
}), KeepOtherLayers);
|
})), KeepOtherLayers);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_link->show();
|
_link->show();
|
||||||
|
@ -825,8 +818,6 @@ _invertOrder(!peer->isChat() && langFirstNameGoesSecond()) {
|
||||||
connect(_first, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
connect(_first, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||||
connect(_last, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
connect(_last, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||||
_last->setVisible(!_peer->isChat());
|
_last->setVisible(!_peer->isChat());
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditNameTitleBox::doSetInnerFocus() {
|
void EditNameTitleBox::doSetInnerFocus() {
|
||||||
|
@ -983,8 +974,6 @@ EditChannelBox::EditChannelBox(ChannelData *channel) : AbstractBox()
|
||||||
connect(_publicLink, SIGNAL(clicked()), this, SLOT(onPublicLink()));
|
connect(_publicLink, SIGNAL(clicked()), this, SLOT(onPublicLink()));
|
||||||
_publicLink->setVisible(_channel->canEditUsername());
|
_publicLink->setVisible(_channel->canEditUsername());
|
||||||
_sign->setVisible(!_channel->isMegagroup());
|
_sign->setVisible(!_channel->isMegagroup());
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditChannelBox::doSetInnerFocus() {
|
void EditChannelBox::doSetInnerFocus() {
|
||||||
|
@ -1163,8 +1152,6 @@ RevokePublicLinkBox::RevokePublicLinkBox(base::lambda<void()> &&revokeCallback)
|
||||||
|
|
||||||
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||||
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
subscribe(FileDownload::ImageLoaded(), [this] { update(); });
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RevokePublicLinkBox::updateMaxHeight() {
|
void RevokePublicLinkBox::updateMaxHeight() {
|
||||||
|
@ -1215,11 +1202,10 @@ void RevokePublicLinkBox::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
QPointer<TWidget> weakThis;
|
QPointer<TWidget> weakThis;
|
||||||
PeerData *pressed;
|
PeerData *pressed;
|
||||||
};
|
};
|
||||||
weakRevokeConfirmBox->setConfirmedCallback([this, data = std_::make_unique<Data>(weakThis(), pressed)]() {
|
weakRevokeConfirmBox->setConfirmedCallback(base::lambda_guarded(this, [this, pressed]() {
|
||||||
if (!data->weakThis) return;
|
|
||||||
if (_revokeRequestId) return;
|
if (_revokeRequestId) return;
|
||||||
_revokeRequestId = MTP::send(MTPchannels_UpdateUsername(data->pressed->asChannel()->inputChannel, MTP_string("")), rpcDone(&RevokePublicLinkBox::revokeLinkDone), rpcFail(&RevokePublicLinkBox::revokeLinkFail));
|
_revokeRequestId = MTP::send(MTPchannels_UpdateUsername(pressed->asChannel()->inputChannel, MTP_string("")), rpcDone(&RevokePublicLinkBox::revokeLinkDone), rpcFail(&RevokePublicLinkBox::revokeLinkFail));
|
||||||
});
|
}));
|
||||||
Ui::showLayer(weakRevokeConfirmBox, KeepOtherLayers);
|
Ui::showLayer(weakRevokeConfirmBox, KeepOtherLayers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,6 @@ AutoLockBox::AutoLockBox() : _close(this, lang(lng_box_ok), st::defaultBoxButton
|
||||||
connect(_close, SIGNAL(clicked()), this, SLOT(onClose()));
|
connect(_close, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||||
|
|
||||||
_close->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close->height());
|
_close->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close->height());
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoLockBox::onChange() {
|
void AutoLockBox::onChange() {
|
||||||
|
|
|
@ -36,7 +36,7 @@ BackgroundBox::BackgroundBox() : ItemListBox(st::backgroundScroll)
|
||||||
|
|
||||||
connect(_inner, SIGNAL(backgroundChosen(int)), this, SLOT(onBackgroundChosen(int)));
|
connect(_inner, SIGNAL(backgroundChosen(int)), this, SLOT(onBackgroundChosen(int)));
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundBox::onBackgroundChosen(int index) {
|
void BackgroundBox::onBackgroundChosen(int index) {
|
||||||
|
|
|
@ -142,8 +142,11 @@ boxTextStyle: TextStyle(defaultTextStyle) {
|
||||||
lineHeight: 22px;
|
lineHeight: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
boxPhotoPadding: margins(28px, 28px, 28px, 18px);
|
boxPhotoTitleFont: font(16px semibold);
|
||||||
boxPhotoCompressedPadding: margins(0px, 2px, 0px, 22px);
|
boxPhotoTitlePosition: point(28px, 26px);
|
||||||
|
boxPhotoPadding: margins(28px, 28px, 28px, 0px);
|
||||||
|
boxPhotoCompressedSkip: 20px;
|
||||||
|
boxPhotoCaptionSkip: 22px;
|
||||||
boxPhotoTextFg: #808080;
|
boxPhotoTextFg: #808080;
|
||||||
|
|
||||||
cropPointSize: 10px;
|
cropPointSize: 10px;
|
||||||
|
|
|
@ -66,8 +66,6 @@ void ConfirmBox::init(const QString &text) {
|
||||||
connect(this, SIGNAL(confirmed()), this, SLOT(onCancel()));
|
connect(this, SIGNAL(confirmed()), this, SLOT(onCancel()));
|
||||||
}
|
}
|
||||||
onTextUpdated();
|
onTextUpdated();
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfirmBox::onConfirmPressed() {
|
void ConfirmBox::onConfirmPressed() {
|
||||||
|
@ -217,8 +215,6 @@ MaxInviteBox::MaxInviteBox(const QString &link) : AbstractBox(st::boxWidth)
|
||||||
setMaxHeight(st::boxPadding.top() + _textHeight + st::boxTextFont->height + st::boxTextFont->height * 2 + st::newGroupLinkPadding.bottom() + st::boxButtonPadding.top() + _close->height() + st::boxButtonPadding.bottom());
|
setMaxHeight(st::boxPadding.top() + _textHeight + st::boxTextFont->height + st::boxTextFont->height * 2 + st::newGroupLinkPadding.bottom() + st::boxButtonPadding.top() + _close->height() + st::boxButtonPadding.bottom());
|
||||||
|
|
||||||
connect(_close, SIGNAL(clicked()), this, SLOT(onClose()));
|
connect(_close, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaxInviteBox::mouseMoveEvent(QMouseEvent *e) {
|
void MaxInviteBox::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
@ -312,8 +308,6 @@ ConvertToSupergroupBox::ConvertToSupergroupBox(ChatData *chat) : AbstractBox(st:
|
||||||
|
|
||||||
connect(_convert, SIGNAL(clicked()), this, SLOT(onConvert()));
|
connect(_convert, SIGNAL(clicked()), this, SLOT(onConvert()));
|
||||||
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConvertToSupergroupBox::onConvert() {
|
void ConvertToSupergroupBox::onConvert() {
|
||||||
|
|
|
@ -124,7 +124,7 @@ void ConfirmPhoneBox::launch() {
|
||||||
connect(&_callTimer, SIGNAL(timeout()), this, SLOT(onCallStatusTimer()));
|
connect(&_callTimer, SIGNAL(timeout()), this, SLOT(onCallStatusTimer()));
|
||||||
|
|
||||||
showChildren();
|
showChildren();
|
||||||
prepare();
|
raiseShadow();
|
||||||
|
|
||||||
Ui::showLayer(this);
|
Ui::showLayer(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,6 @@ ConnectionBox::ConnectionBox() : AbstractBox(st::boxWidth, lang(lng_connection_h
|
||||||
connect(_passwordInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
connect(_passwordInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||||
|
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionBox::updateControlsVisibility() {
|
void ConnectionBox::updateControlsVisibility() {
|
||||||
|
@ -218,8 +216,6 @@ AutoDownloadBox::AutoDownloadBox() : AbstractBox(st::boxWidth)
|
||||||
|
|
||||||
connect(_save, SIGNAL(clicked()), this, SLOT(onSave()));
|
connect(_save, SIGNAL(clicked()), this, SLOT(onSave()));
|
||||||
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoDownloadBox::paintEvent(QPaintEvent *e) {
|
void AutoDownloadBox::paintEvent(QPaintEvent *e) {
|
||||||
|
|
|
@ -172,7 +172,7 @@ void ContactsBox::init() {
|
||||||
_searchTimer.setSingleShot(true);
|
_searchTimer.setSingleShot(true);
|
||||||
connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchByUsername()));
|
connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchByUsername()));
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContactsBox::onSearchByUsername(bool searchCache) {
|
bool ContactsBox::onSearchByUsername(bool searchCache) {
|
||||||
|
|
|
@ -52,8 +52,6 @@ DownloadPathBox::DownloadPathBox() : AbstractBox()
|
||||||
setPathText(QDir::toNativeSeparators(_path));
|
setPathText(QDir::toNativeSeparators(_path));
|
||||||
}
|
}
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadPathBox::updateControlsVisibility() {
|
void DownloadPathBox::updateControlsVisibility() {
|
||||||
|
|
|
@ -81,7 +81,7 @@ EmojiBox::EmojiBox() : _esize(EmojiSizes[EIndex + 1]) {
|
||||||
|
|
||||||
resizeMaxHeight(_blocks[0].size() * st::emojiReplaceWidth + 2 * st::emojiReplacePadding, titleHeight() + st::emojiReplacePadding + _blocks.size() * st::emojiReplaceHeight + (st::emojiReplaceHeight - _blockHeight) + st::emojiReplacePadding);
|
resizeMaxHeight(_blocks[0].size() * st::emojiReplaceWidth + 2 * st::emojiReplacePadding, titleHeight() + st::emojiReplacePadding + _blocks.size() * st::emojiReplaceHeight + (st::emojiReplaceHeight - _blockHeight) + st::emojiReplacePadding);
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiBox::fillBlocks() {
|
void EmojiBox::fillBlocks() {
|
||||||
|
|
|
@ -64,7 +64,6 @@ _close(this, lang(lng_box_ok), st::defaultBoxButton) {
|
||||||
connect(_close, SIGNAL(clicked()), this, SLOT(onClose()));
|
connect(_close, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||||
|
|
||||||
_close->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close->height());
|
_close->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close->height());
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageBox::mousePressEvent(QMouseEvent *e) {
|
void LanguageBox::mousePressEvent(QMouseEvent *e) {
|
||||||
|
|
|
@ -43,7 +43,6 @@ LocalStorageBox::LocalStorageBox() : AbstractBox()
|
||||||
updateControls();
|
updateControls();
|
||||||
|
|
||||||
checkLocalStoredCounts();
|
checkLocalStoredCounts();
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalStorageBox::updateControls() {
|
void LocalStorageBox::updateControls() {
|
||||||
|
|
|
@ -75,7 +75,7 @@ MembersBox::MembersBox(ChannelData *channel, MembersFilter filter) : ItemListBox
|
||||||
|
|
||||||
connect(&_loadTimer, SIGNAL(timeout()), _inner, SLOT(load()));
|
connect(&_loadTimer, SIGNAL(timeout()), _inner, SLOT(load()));
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MembersBox::keyPressEvent(QKeyEvent *e) {
|
void MembersBox::keyPressEvent(QKeyEvent *e) {
|
||||||
|
|
|
@ -127,8 +127,6 @@ NotificationsBox::NotificationsBox() : AbstractBox()
|
||||||
prepareNotificationSampleSmall();
|
prepareNotificationSampleSmall();
|
||||||
prepareNotificationSampleLarge();
|
prepareNotificationSampleLarge();
|
||||||
setMaxHeight(st::notificationsBoxHeight);
|
setMaxHeight(st::notificationsBoxHeight);
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotificationsBox::paintEvent(QPaintEvent *e) {
|
void NotificationsBox::paintEvent(QPaintEvent *e) {
|
||||||
|
|
|
@ -114,7 +114,7 @@ void PasscodeBox::init() {
|
||||||
_passwordHint->setVisible(!_turningOff && _cloudPwd);
|
_passwordHint->setVisible(!_turningOff && _cloudPwd);
|
||||||
_recoverEmail->setVisible(!_turningOff && _cloudPwd && _curSalt.isEmpty());
|
_recoverEmail->setVisible(!_turningOff && _cloudPwd && _curSalt.isEmpty());
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PasscodeBox::onSubmit() {
|
void PasscodeBox::onSubmit() {
|
||||||
|
@ -463,7 +463,7 @@ RecoverBox::RecoverBox(const QString &pattern) : AbstractBox(st::boxWidth, lang(
|
||||||
connect(_recoverCode, SIGNAL(changed()), this, SLOT(onCodeChanged()));
|
connect(_recoverCode, SIGNAL(changed()), this, SLOT(onCodeChanged()));
|
||||||
connect(_recoverCode, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
connect(_recoverCode, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecoverBox::paintEvent(QPaintEvent *e) {
|
void RecoverBox::paintEvent(QPaintEvent *e) {
|
||||||
|
|
|
@ -49,8 +49,6 @@ ReportBox::ReportBox(ChannelData *channel) : AbstractBox(st::boxWidth)
|
||||||
connect(_reasonOther, SIGNAL(changed()), this, SLOT(onChange()));
|
connect(_reasonOther, SIGNAL(changed()), this, SLOT(onChange()));
|
||||||
|
|
||||||
updateMaxHeight();
|
updateMaxHeight();
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReportBox::resizeEvent(QResizeEvent *e) {
|
void ReportBox::resizeEvent(QResizeEvent *e) {
|
||||||
|
|
|
@ -19,63 +19,51 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "boxes/photosendbox.h"
|
#include "boxes/send_files_box.h"
|
||||||
|
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "photosendbox.h"
|
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
|
#include "ui/filedialog.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
|
||||||
PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxWideWidth)
|
namespace {
|
||||||
, _file(file)
|
|
||||||
, _animated(false)
|
|
||||||
, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption))
|
|
||||||
, _compressedFromSettings(_file->type == PrepareAuto)
|
|
||||||
, _compressed(this, lang(lng_send_image_compressed), _compressedFromSettings ? cCompressPastedImage() : true, st::defaultBoxCheckbox)
|
|
||||||
, _send(this, lang(lng_send_button), st::defaultBoxButton)
|
|
||||||
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
|
|
||||||
, _thumbx(0)
|
|
||||||
, _thumby(0)
|
|
||||||
, _thumbw(0)
|
|
||||||
, _thumbh(0)
|
|
||||||
, _statusw(0)
|
|
||||||
, _isImage(false)
|
|
||||||
, _replyTo(_file->to.replyTo)
|
|
||||||
, _confirmed(false) {
|
|
||||||
connect(_send, SIGNAL(clicked()), this, SLOT(onSend()));
|
|
||||||
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
|
||||||
|
|
||||||
_animated = false;
|
constexpr auto kMinPreviewWidth = 20;
|
||||||
QSize dimensions;
|
|
||||||
if (_file->photo.type() != mtpc_photoEmpty) {
|
} // namespace
|
||||||
_file->type = PreparePhoto;
|
|
||||||
} else if (_file->document.type() == mtpc_document) {
|
SendFilesBox::SendFilesBox(const QString &filepath, QImage image, CompressConfirm compressed, bool animated) : AbstractBox(st::boxWideWidth)
|
||||||
const auto &document(_file->document.c_document());
|
, _files(filepath)
|
||||||
const auto &attributes(document.vattributes.c_vector().v);
|
, _image(image)
|
||||||
for (int32 i = 0, l = attributes.size(); i < l; ++i) {
|
, _compressConfirm(compressed)
|
||||||
if (attributes.at(i).type() == mtpc_documentAttributeAnimated) {
|
, _animated(image.isNull() ? false : animated)
|
||||||
_animated = true;
|
, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption))
|
||||||
} else if (attributes.at(i).type() == mtpc_documentAttributeImageSize) {
|
, _send(this, lang(lng_send_button), st::defaultBoxButton)
|
||||||
dimensions = QSize(attributes.at(i).c_documentAttributeImageSize().vw.v, attributes.at(i).c_documentAttributeImageSize().vh.v);
|
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
|
||||||
} else if (attributes.at(i).type() == mtpc_documentAttributeVideo) {
|
if (!image.isNull()) {
|
||||||
dimensions = QSize(attributes.at(i).c_documentAttributeVideo().vw.v, attributes.at(i).c_documentAttributeVideo().vh.v);
|
if (!_animated && _compressConfirm == CompressConfirm::None) {
|
||||||
|
auto originalWidth = image.width();
|
||||||
|
auto originalHeight = image.height();
|
||||||
|
auto thumbWidth = st::msgFileThumbSize;
|
||||||
|
if (originalWidth > originalHeight) {
|
||||||
|
thumbWidth = (originalWidth * st::msgFileThumbSize) / originalHeight;
|
||||||
}
|
}
|
||||||
}
|
auto options = Images::Option::Smooth | Images::Option::RoundedSmall | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::RoundedBottomLeft | Images::Option::RoundedBottomRight;
|
||||||
if (dimensions.isEmpty()) _animated = false;
|
_fileThumb = Images::pixmap(image, thumbWidth * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, st::msgFileThumbSize);
|
||||||
}
|
} else {
|
||||||
if (_file->type == PreparePhoto || _animated) {
|
auto maxW = 0;
|
||||||
int32 maxW = 0, maxH = 0;
|
auto maxH = 0;
|
||||||
if (_animated) {
|
if (_animated) {
|
||||||
int32 limitW = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
auto limitW = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
||||||
int32 limitH = st::confirmMaxHeight;
|
auto limitH = st::confirmMaxHeight;
|
||||||
maxW = qMax(dimensions.width(), 1);
|
maxW = qMax(image.width(), 1);
|
||||||
maxH = qMax(dimensions.height(), 1);
|
maxH = qMax(image.height(), 1);
|
||||||
if (maxW * limitH > maxH * limitW) {
|
if (maxW * limitH > maxH * limitW) {
|
||||||
if (maxW < limitW) {
|
if (maxW < limitW) {
|
||||||
maxH = maxH * limitW / maxW;
|
maxH = maxH * limitW / maxW;
|
||||||
|
@ -87,131 +75,145 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
|
||||||
maxH = limitH;
|
maxH = limitH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_thumb = imagePix(_file->thumb.toImage(), maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixOption::Smooth | ImagePixOption::Blurred, maxW, maxH);
|
image = Images::prepare(image, maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), Images::Option::Smooth | Images::Option::Blurred, maxW, maxH);
|
||||||
} else {
|
|
||||||
for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) {
|
|
||||||
if (i->width() >= maxW && i->height() >= maxH) {
|
|
||||||
_thumb = *i;
|
|
||||||
maxW = _thumb.width();
|
|
||||||
maxH = _thumb.height();
|
|
||||||
}
|
}
|
||||||
|
auto originalWidth = image.width();
|
||||||
|
auto originalHeight = image.height();
|
||||||
|
if (!originalWidth || !originalHeight) {
|
||||||
|
originalWidth = originalHeight = 1;
|
||||||
}
|
}
|
||||||
|
_previewWidth = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
||||||
|
if (image.width() < _previewWidth) {
|
||||||
|
_previewWidth = qMax(image.width(), kMinPreviewWidth);
|
||||||
}
|
}
|
||||||
int32 tw = _thumb.width(), th = _thumb.height();
|
auto maxthumbh = qMin(qRound(1.5 * _previewWidth), st::confirmMaxHeight);
|
||||||
if (!tw || !th) {
|
_previewHeight = qRound(originalHeight * float64(_previewWidth) / originalWidth);
|
||||||
tw = th = 1;
|
if (_previewHeight > maxthumbh) {
|
||||||
|
_previewWidth = qRound(_previewWidth * float64(maxthumbh) / _previewHeight);
|
||||||
|
accumulate_max(_previewWidth, kMinPreviewWidth);
|
||||||
|
_previewHeight = maxthumbh;
|
||||||
}
|
}
|
||||||
_thumbw = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
_previewLeft = (width() - _previewWidth) / 2;
|
||||||
if (_thumb.width() < _thumbw) {
|
|
||||||
_thumbw = (_thumb.width() > 20) ? _thumb.width() : 20;
|
|
||||||
}
|
|
||||||
int32 maxthumbh = qMin(qRound(1.5 * _thumbw), int(st::confirmMaxHeight));
|
|
||||||
_thumbh = qRound(th * float64(_thumbw) / tw);
|
|
||||||
if (_thumbh > maxthumbh) {
|
|
||||||
_thumbw = qRound(_thumbw * float64(maxthumbh) / _thumbh);
|
|
||||||
_thumbh = maxthumbh;
|
|
||||||
if (_thumbw < 10) {
|
|
||||||
_thumbw = 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_thumbx = (width() - _thumbw) / 2;
|
|
||||||
|
|
||||||
_thumb = App::pixmapFromImageInPlace(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
image = std_::move(image).scaled(_previewWidth * cIntRetinaFactor(), _previewHeight * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||||
_thumb.setDevicePixelRatio(cRetinaFactor());
|
image = Images::prepareOpaque(std_::move(image));
|
||||||
} else {
|
_preview = App::pixmapFromImageInPlace(std_::move(image));
|
||||||
if (_file->thumb.isNull()) {
|
_preview.setDevicePixelRatio(cRetinaFactor());
|
||||||
_thumbw = 0;
|
}
|
||||||
} else {
|
}
|
||||||
_thumb = _file->thumb;
|
if (_preview.isNull()) {
|
||||||
int32 tw = _thumb.width(), th = _thumb.height();
|
if (filepath.isEmpty()) {
|
||||||
if (tw > th) {
|
auto filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
|
||||||
_thumbw = (tw * st::msgFileThumbSize) / th;
|
_nameText.setText(st::semiboldFont, filename, _textNameOptions);
|
||||||
} else {
|
_statusText = qsl("%1x%2").arg(_image.width()).arg(_image.height());
|
||||||
_thumbw = st::msgFileThumbSize;
|
_statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText));
|
||||||
|
_fileIsImage = true;
|
||||||
|
} else {
|
||||||
|
auto fileinfo = QFileInfo(filepath);
|
||||||
|
auto filename = fileinfo.fileName();
|
||||||
|
_nameText.setText(st::semiboldFont, filename, _textNameOptions);
|
||||||
|
_statusText = formatSizeText(fileinfo.size());
|
||||||
|
_statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText));
|
||||||
|
_fileIsImage = fileIsImage(filename, mimeTypeForFile(fileinfo).name());
|
||||||
}
|
}
|
||||||
auto options = ImagePixOption::Smooth | ImagePixOption::RoundedSmall | ImagePixOption::RoundedTopLeft | ImagePixOption::RoundedTopRight | ImagePixOption::RoundedBottomLeft | ImagePixOption::RoundedBottomRight;
|
|
||||||
_thumb = imagePix(_thumb.toImage(), _thumbw * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, st::msgFileThumbSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_name.setText(st::semiboldFont, _file->filename, _textNameOptions);
|
setup();
|
||||||
_status = formatSizeText(_file->filesize);
|
}
|
||||||
_statusw = qMax(_name.maxWidth(), st::normalFont->width(_status));
|
|
||||||
_isImage = fileIsImage(_file->filename, _file->filemime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_file->type != PreparePhoto) {
|
SendFilesBox::SendFilesBox(const QStringList &files, CompressConfirm compressed) : AbstractBox(st::boxWideWidth)
|
||||||
_compressed->hide();
|
, _files(files)
|
||||||
}
|
, _compressConfirm(compressed)
|
||||||
|
, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption))
|
||||||
|
, _send(this, lang(lng_send_button), st::defaultBoxButton)
|
||||||
|
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
|
||||||
|
updateTitleText();
|
||||||
|
|
||||||
updateBoxSize();
|
setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
SendFilesBox::SendFilesBox(const QString &phone, const QString &firstname, const QString &lastname) : AbstractBox(st::boxWideWidth)
|
||||||
|
, _contactPhone(phone)
|
||||||
|
, _contactFirstName(firstname)
|
||||||
|
, _contactLastName(lastname)
|
||||||
|
, _send(this, lang(lng_send_button), st::defaultBoxButton)
|
||||||
|
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
|
||||||
|
_nameText.setText(st::semiboldFont, lng_full_name(lt_first_name, _contactFirstName, lt_last_name, _contactLastName), _textNameOptions);
|
||||||
|
_statusText = _contactPhone;
|
||||||
|
_statusWidth = qMax(_nameText.maxWidth(), st::normalFont->width(_statusText));
|
||||||
|
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendFilesBox::setup() {
|
||||||
|
_send->setClickedCallback([this] { onSend(); });
|
||||||
|
_cancel->setClickedCallback([this] { onClose(); });
|
||||||
|
|
||||||
|
if (_compressConfirm != CompressConfirm::None) {
|
||||||
|
auto compressed = (_compressConfirm == CompressConfirm::Auto) ? cCompressPastedImage() : (_compressConfirm == CompressConfirm::Yes);
|
||||||
|
auto text = lng_send_images_compress(lt_count, _files.size());
|
||||||
|
_compressed.create(this, text, compressed, st::defaultBoxCheckbox);
|
||||||
|
connect(_compressed, SIGNAL(changed()), this, SLOT(onCompressedChange()));
|
||||||
|
}
|
||||||
|
if (_caption) {
|
||||||
_caption->setMaxLength(MaxPhotoCaption);
|
_caption->setMaxLength(MaxPhotoCaption);
|
||||||
_caption->setCtrlEnterSubmit(Ui::CtrlEnterSubmitBoth);
|
_caption->setCtrlEnterSubmit(Ui::CtrlEnterSubmitBoth);
|
||||||
connect(_compressed, SIGNAL(changed()), this, SLOT(onCompressedChange()));
|
|
||||||
connect(_caption, SIGNAL(resized()), this, SLOT(onCaptionResized()));
|
connect(_caption, SIGNAL(resized()), this, SLOT(onCaptionResized()));
|
||||||
connect(_caption, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
|
connect(_caption, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
|
||||||
connect(_caption, SIGNAL(cancelled()), this, SLOT(onClose()));
|
connect(_caption, SIGNAL(cancelled()), this, SLOT(onClose()));
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
PhotoSendBox::PhotoSendBox(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo) : AbstractBox(st::boxWideWidth)
|
|
||||||
, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption))
|
|
||||||
, _compressed(this, lang(lng_send_image_compressed), true)
|
|
||||||
, _send(this, lang(lng_send_button), st::defaultBoxButton)
|
|
||||||
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
|
|
||||||
, _thumbx(0)
|
|
||||||
, _thumby(0)
|
|
||||||
, _thumbw(0)
|
|
||||||
, _thumbh(0)
|
|
||||||
, _statusw(0)
|
|
||||||
, _isImage(false)
|
|
||||||
, _phone(phone)
|
|
||||||
, _fname(fname)
|
|
||||||
, _lname(lname)
|
|
||||||
, _replyTo(replyTo)
|
|
||||||
, _confirmed(false) {
|
|
||||||
connect(_send, SIGNAL(clicked()), this, SLOT(onSend()));
|
|
||||||
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
|
||||||
|
|
||||||
_compressed->hide();
|
|
||||||
_caption->hide();
|
|
||||||
|
|
||||||
_name.setText(st::semiboldFont, lng_full_name(lt_first_name, _fname, lt_last_name, _lname), _textNameOptions);
|
|
||||||
_status = _phone;
|
|
||||||
_statusw = qMax(_name.maxWidth(), st::normalFont->width(_status));
|
|
||||||
|
|
||||||
updateBoxSize();
|
|
||||||
prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhotoSendBox::onCompressedChange() {
|
|
||||||
if (_caption->isHidden()) {
|
|
||||||
setFocus();
|
|
||||||
} else {
|
|
||||||
_caption->setFocus();
|
|
||||||
}
|
}
|
||||||
|
_send->setText(getSendButtonText());
|
||||||
updateBoxSize();
|
updateBoxSize();
|
||||||
resizeEvent(0);
|
}
|
||||||
|
|
||||||
|
QString SendFilesBox::getSendButtonText() const {
|
||||||
|
if (!_contactPhone.isEmpty()) {
|
||||||
|
return lang(lng_send_button);
|
||||||
|
} else if (_compressed && _compressed->checked()) {
|
||||||
|
return lng_send_photos(lt_count, _files.size());
|
||||||
|
}
|
||||||
|
return lng_send_files(lt_count, _files.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendFilesBox::onCompressedChange() {
|
||||||
|
doSetInnerFocus();
|
||||||
|
_send->setText(getSendButtonText());
|
||||||
|
updateControlsGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendFilesBox::onCaptionResized() {
|
||||||
|
updateBoxSize();
|
||||||
|
updateControlsGeometry();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoSendBox::onCaptionResized() {
|
void SendFilesBox::updateTitleText() {
|
||||||
updateBoxSize();
|
_titleText = (_compressConfirm == CompressConfirm::None) ? lng_send_files_selected(lt_count, _files.size()) : lng_send_images_selected(lt_count, _files.size());
|
||||||
resizeEvent(0);
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoSendBox::updateBoxSize() {
|
void SendFilesBox::updateBoxSize() {
|
||||||
if (_file && (_file->type == PreparePhoto || _animated)) {
|
auto newHeight = 0;
|
||||||
setMaxHeight(st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + (_animated ? 0 : (st::boxPhotoCompressedPadding.top() + _compressed->height())) + st::boxPhotoCompressedPadding.bottom() + _caption->height() + st::boxButtonPadding.top() + _send->height() + st::boxButtonPadding.bottom());
|
if (!_preview.isNull()) {
|
||||||
} else if (_thumbw) {
|
newHeight += st::boxPhotoPadding.top() + _previewHeight;
|
||||||
setMaxHeight(st::boxPhotoPadding.top() + st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom() + (_file ? (st::boxPhotoCompressedPadding.bottom() + _caption->height()) : 0) + st::boxPhotoPadding.bottom() + st::boxButtonPadding.top() + _send->height() + st::boxButtonPadding.bottom());
|
} else if (!_fileThumb.isNull()) {
|
||||||
|
newHeight += st::boxPhotoPadding.top() + st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom();
|
||||||
|
} else if (_files.size() > 1) {
|
||||||
|
newHeight += titleHeight();
|
||||||
} else {
|
} else {
|
||||||
setMaxHeight(st::boxPhotoPadding.top() + st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom() + (_file ? (st::boxPhotoCompressedPadding.bottom() + _caption->height()) : 0) + st::boxPhotoPadding.bottom() + st::boxButtonPadding.top() + _send->height() + st::boxButtonPadding.bottom());
|
newHeight += st::boxPhotoPadding.top() + st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom();
|
||||||
}
|
}
|
||||||
|
if (_compressed) {
|
||||||
|
newHeight += st::boxPhotoCompressedSkip + _compressed->height();
|
||||||
|
}
|
||||||
|
if (_caption) {
|
||||||
|
newHeight += st::boxPhotoCaptionSkip + _caption->height();
|
||||||
|
}
|
||||||
|
newHeight += st::boxButtonPadding.top() + _send->height() + st::boxButtonPadding.bottom();
|
||||||
|
setMaxHeight(newHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoSendBox::keyPressEvent(QKeyEvent *e) {
|
void SendFilesBox::keyPressEvent(QKeyEvent *e) {
|
||||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||||
onSend((e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier)) && e->modifiers().testFlag(Qt::ShiftModifier));
|
onSend((e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier)) && e->modifiers().testFlag(Qt::ShiftModifier));
|
||||||
} else {
|
} else {
|
||||||
|
@ -219,21 +221,27 @@ void PhotoSendBox::keyPressEvent(QKeyEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoSendBox::paintEvent(QPaintEvent *e) {
|
void SendFilesBox::paintEvent(QPaintEvent *e) {
|
||||||
AbstractBox::paintEvent(e);
|
AbstractBox::paintEvent(e);
|
||||||
|
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
if (_file && (_file->type == PreparePhoto || _animated)) {
|
if (!_titleText.isEmpty()) {
|
||||||
if (_thumbx > st::boxPhotoPadding.left()) {
|
p.setFont(st::boxPhotoTitleFont);
|
||||||
p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), _thumbh, st::confirmBg->b);
|
p.setPen(st::boxTitleFg);
|
||||||
|
p.drawTextLeft(st::boxPhotoTitlePosition.x(), st::boxPhotoTitlePosition.y(), width(), _titleText);
|
||||||
}
|
}
|
||||||
if (_thumbx + _thumbw < width() - st::boxPhotoPadding.right()) {
|
|
||||||
p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, _thumbh, st::confirmBg->b);
|
if (!_preview.isNull()) {
|
||||||
|
if (_previewLeft > st::boxPhotoPadding.left()) {
|
||||||
|
p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _previewLeft - st::boxPhotoPadding.left(), _previewHeight, st::confirmBg);
|
||||||
}
|
}
|
||||||
p.drawPixmap(_thumbx, st::boxPhotoPadding.top(), _thumb);
|
if (_previewLeft + _previewWidth < width() - st::boxPhotoPadding.right()) {
|
||||||
|
p.fillRect(_previewLeft + _previewWidth, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _previewLeft - _previewWidth, _previewHeight, st::confirmBg);
|
||||||
|
}
|
||||||
|
p.drawPixmap(_previewLeft, st::boxPhotoPadding.top(), _preview);
|
||||||
if (_animated) {
|
if (_animated) {
|
||||||
QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_thumbh - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
|
auto inner = QRect(_previewLeft + (_previewWidth - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_previewHeight - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(st::msgDateImgBg);
|
p.setBrush(st::msgDateImgBg);
|
||||||
|
|
||||||
|
@ -244,35 +252,29 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) {
|
||||||
auto icon = &st::historyFileInPlay;
|
auto icon = &st::historyFileInPlay;
|
||||||
icon->paintInCenter(p, inner);
|
icon->paintInCenter(p, inner);
|
||||||
}
|
}
|
||||||
|
} else if (_files.size() < 2) {
|
||||||
|
auto w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
||||||
|
auto h = _fileThumb.isNull() ? (st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom()) : (st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom());
|
||||||
|
auto nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0;
|
||||||
|
if (_fileThumb.isNull()) {
|
||||||
|
nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right();
|
||||||
|
nametop = st::msgFileNameTop;
|
||||||
|
nameright = st::msgFilePadding.left();
|
||||||
|
statustop = st::msgFileStatusTop;
|
||||||
} else {
|
} else {
|
||||||
int32 w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
|
||||||
int32 h = _thumbw ? (st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom()) : (st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom());
|
|
||||||
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0;
|
|
||||||
if (_thumbw) {
|
|
||||||
nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right();
|
nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right();
|
||||||
nametop = st::msgFileThumbNameTop;
|
nametop = st::msgFileThumbNameTop;
|
||||||
nameright = st::msgFileThumbPadding.left();
|
nameright = st::msgFileThumbPadding.left();
|
||||||
statustop = st::msgFileThumbStatusTop;
|
statustop = st::msgFileThumbStatusTop;
|
||||||
linktop = st::msgFileThumbLinkTop;
|
linktop = st::msgFileThumbLinkTop;
|
||||||
} else {
|
|
||||||
nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right();
|
|
||||||
nametop = st::msgFileNameTop;
|
|
||||||
nameright = st::msgFilePadding.left();
|
|
||||||
statustop = st::msgFileStatusTop;
|
|
||||||
}
|
|
||||||
int32 namewidth = w - nameleft - (_thumbw ? st::msgFileThumbPadding.left() : st::msgFilePadding.left());
|
|
||||||
if (namewidth > _statusw) {
|
|
||||||
w -= (namewidth - _statusw);
|
|
||||||
namewidth = _statusw;
|
|
||||||
}
|
}
|
||||||
|
auto namewidth = w - nameleft - (_fileThumb.isNull() ? st::msgFilePadding.left() : st::msgFileThumbPadding.left());
|
||||||
int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top();
|
int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top();
|
||||||
|
|
||||||
App::roundRect(p, x, y, w, h, st::msgOutBg, MessageOutCorners, &st::msgOutShadow);
|
App::roundRect(p, x, y, w, h, st::msgOutBg, MessageOutCorners, &st::msgOutShadow);
|
||||||
|
|
||||||
if (_thumbw) {
|
if (_fileThumb.isNull()) {
|
||||||
QRect rthumb(rtlrect(x + st::msgFileThumbPadding.left(), y + st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, width()));
|
if (_contactPhone.isNull()) {
|
||||||
p.drawPixmap(rthumb.topLeft(), _thumb);
|
|
||||||
} else if (_file) {
|
|
||||||
QRect inner(rtlrect(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width()));
|
QRect inner(rtlrect(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width()));
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(st::msgFileOutBg);
|
p.setBrush(st::msgFileOutBg);
|
||||||
|
@ -281,79 +283,74 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) {
|
||||||
p.drawEllipse(inner);
|
p.drawEllipse(inner);
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||||
|
|
||||||
auto icon = &(_isImage ? st::historyFileOutImage : st::historyFileOutDocument);
|
auto &icon = _fileIsImage ? st::historyFileOutImage : st::historyFileOutDocument;
|
||||||
icon->paintInCenter(p, inner);
|
icon.paintInCenter(p, inner);
|
||||||
} else {
|
} else {
|
||||||
p.drawPixmapLeft(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), userDefPhoto(1)->pixCircled(st::msgFileSize));
|
p.drawPixmapLeft(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), userDefPhoto(1)->pixCircled(st::msgFileSize));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
QRect rthumb(rtlrect(x + st::msgFileThumbPadding.left(), y + st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, width()));
|
||||||
|
p.drawPixmap(rthumb.topLeft(), _fileThumb);
|
||||||
|
}
|
||||||
p.setFont(st::semiboldFont);
|
p.setFont(st::semiboldFont);
|
||||||
p.setPen(st::historyFileNameOutFg);
|
p.setPen(st::historyFileNameOutFg);
|
||||||
_name.drawLeftElided(p, x + nameleft, y + nametop, namewidth, width());
|
_nameText.drawLeftElided(p, x + nameleft, y + nametop, namewidth, width());
|
||||||
|
|
||||||
auto &status = st::mediaOutFg;
|
auto &status = st::mediaOutFg;
|
||||||
p.setFont(st::normalFont);
|
p.setFont(st::normalFont);
|
||||||
p.setPen(status);
|
p.setPen(status);
|
||||||
p.drawTextLeft(x + nameleft, y + statustop, width(), _status);
|
p.drawTextLeft(x + nameleft, y + statustop, width(), _statusText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoSendBox::resizeEvent(QResizeEvent *e) {
|
void SendFilesBox::resizeEvent(QResizeEvent *e) {
|
||||||
_send->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _send->height());
|
updateControlsGeometry();
|
||||||
_cancel->moveToRight(st::boxButtonPadding.right() + _send->width() + st::boxButtonPadding.left(), _send->y());
|
|
||||||
_caption->resize(st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), _caption->height());
|
|
||||||
_caption->moveToLeft(st::boxPhotoPadding.left(), _send->y() - st::boxButtonPadding.top() - _caption->height());
|
|
||||||
_compressed->moveToLeft(st::boxPhotoPadding.left(), st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + st::boxPhotoCompressedPadding.top());
|
|
||||||
AbstractBox::resizeEvent(e);
|
AbstractBox::resizeEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoSendBox::closePressed() {
|
void SendFilesBox::updateControlsGeometry() {
|
||||||
if (!_confirmed && App::main()) {
|
_send->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _send->height());
|
||||||
if (_file) {
|
_cancel->moveToRight(st::boxButtonPadding.right() + _send->width() + st::boxButtonPadding.left(), _send->y());
|
||||||
App::main()->onSendFileCancel(_file);
|
auto bottom = _send->y() - st::boxButtonPadding.top();
|
||||||
} else {
|
if (_caption) {
|
||||||
App::main()->onShareContactCancel();
|
_caption->resize(st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), _caption->height());
|
||||||
|
_caption->moveToLeft(st::boxPhotoPadding.left(), bottom - _caption->height());
|
||||||
|
bottom -= st::boxPhotoCaptionSkip + _caption->height();
|
||||||
}
|
}
|
||||||
|
if (_compressed) {
|
||||||
|
_compressed->moveToLeft(st::boxPhotoPadding.left(), bottom - _compressed->height());
|
||||||
|
bottom -= st::boxPhotoCompressedSkip + _compressed->height();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoSendBox::doSetInnerFocus() {
|
void SendFilesBox::doSetInnerFocus() {
|
||||||
if (_caption->isHidden()) {
|
if (!_caption || _caption->isHidden()) {
|
||||||
setFocus();
|
setFocus();
|
||||||
} else {
|
} else {
|
||||||
_caption->setFocus();
|
_caption->setFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoSendBox::onSend(bool ctrlShiftEnter) {
|
void SendFilesBox::onSend(bool ctrlShiftEnter) {
|
||||||
if (App::main()) {
|
if (_compressed && _compressConfirm == CompressConfirm::Auto && _compressed->checked() != cCompressPastedImage()) {
|
||||||
if (_file) {
|
|
||||||
if (_compressed->isHidden()) {
|
|
||||||
if (_file->type == PrepareAuto) {
|
|
||||||
_file->type = PrepareDocument;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (_compressedFromSettings && _compressed->checked() != cCompressPastedImage()) {
|
|
||||||
cSetCompressPastedImage(_compressed->checked());
|
cSetCompressPastedImage(_compressed->checked());
|
||||||
Local::writeUserSettings();
|
Local::writeUserSettings();
|
||||||
}
|
}
|
||||||
if (_compressed->checked()) {
|
|
||||||
_file->type = PreparePhoto;
|
|
||||||
} else {
|
|
||||||
_file->type = PrepareDocument;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!_caption->isHidden()) {
|
|
||||||
_file->caption = prepareText(_caption->getLastText(), true);
|
|
||||||
}
|
|
||||||
App::main()->onSendFileConfirm(_file, ctrlShiftEnter);
|
|
||||||
} else {
|
|
||||||
App::main()->onShareContactConfirm(_phone, _fname, _lname, _replyTo, ctrlShiftEnter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_confirmed = true;
|
_confirmed = true;
|
||||||
|
if (_confirmedCallback) {
|
||||||
|
auto compressed = _compressed ? _compressed->checked() : false;
|
||||||
|
auto caption = _caption ? prepareText(_caption->getLastText(), true) : QString();
|
||||||
|
_confirmedCallback(_files, compressed, caption, ctrlShiftEnter);
|
||||||
|
}
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SendFilesBox::closePressed() {
|
||||||
|
if (!_confirmed && _cancelledCallback) {
|
||||||
|
_cancelledCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth)
|
EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth)
|
||||||
, _msgId(msg->fullId())
|
, _msgId(msg->fullId())
|
||||||
, _animated(false)
|
, _animated(false)
|
||||||
|
@ -421,8 +418,8 @@ EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth)
|
||||||
} else {
|
} else {
|
||||||
_thumbw = st::msgFileThumbSize;
|
_thumbw = st::msgFileThumbSize;
|
||||||
}
|
}
|
||||||
auto options = ImagePixOption::Smooth | ImagePixOption::RoundedSmall | ImagePixOption::RoundedTopLeft | ImagePixOption::RoundedTopRight | ImagePixOption::RoundedBottomLeft | ImagePixOption::RoundedBottomRight;
|
auto options = Images::Option::Smooth | Images::Option::RoundedSmall | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::RoundedBottomLeft | Images::Option::RoundedBottomRight;
|
||||||
_thumb = imagePix(image->pix().toImage(), _thumbw * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, st::msgFileThumbSize);
|
_thumb = Images::pixmap(image->pix().toImage(), _thumbw * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, st::msgFileThumbSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doc) {
|
if (doc) {
|
||||||
|
@ -453,11 +450,11 @@ EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth)
|
||||||
maxH = limitH;
|
maxH = limitH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixOption::Smooth | ImagePixOption::Blurred, maxW, maxH);
|
_thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), Images::Option::Smooth | Images::Option::Blurred, maxW, maxH);
|
||||||
} else {
|
} else {
|
||||||
maxW = dimensions.width();
|
maxW = dimensions.width();
|
||||||
maxH = dimensions.height();
|
maxH = dimensions.height();
|
||||||
_thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixOption::Smooth, maxW, maxH);
|
_thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), Images::Option::Smooth, maxW, maxH);
|
||||||
}
|
}
|
||||||
int32 tw = _thumb.width(), th = _thumb.height();
|
int32 tw = _thumb.width(), th = _thumb.height();
|
||||||
if (!tw || !th) {
|
if (!tw || !th) {
|
||||||
|
@ -501,8 +498,6 @@ EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth)
|
||||||
QTextCursor c(_field->textCursor());
|
QTextCursor c(_field->textCursor());
|
||||||
c.movePosition(QTextCursor::End);
|
c.movePosition(QTextCursor::End);
|
||||||
_field->setTextCursor(c);
|
_field->setTextCursor(c);
|
||||||
|
|
||||||
prepare();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditCaptionBox::captionFound() const {
|
bool EditCaptionBox::captionFound() const {
|
||||||
|
@ -516,7 +511,7 @@ void EditCaptionBox::onCaptionResized() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditCaptionBox::updateBoxSize() {
|
void EditCaptionBox::updateBoxSize() {
|
||||||
int32 bottomh = st::boxPhotoCompressedPadding.bottom() + _field->height() + st::normalFont->height + st::boxButtonPadding.top() + _save->height() + st::boxButtonPadding.bottom();
|
auto bottomh = st::boxPhotoCaptionSkip + _field->height() + st::normalFont->height + st::boxButtonPadding.top() + _save->height() + st::boxButtonPadding.bottom();
|
||||||
if (_photo || _animated) {
|
if (_photo || _animated) {
|
||||||
setMaxHeight(st::boxPhotoPadding.top() + _thumbh + bottomh);
|
setMaxHeight(st::boxPhotoPadding.top() + _thumbh + bottomh);
|
||||||
} else if (_thumbw) {
|
} else if (_thumbw) {
|
|
@ -29,17 +29,25 @@ class RoundButton;
|
||||||
class InputArea;
|
class InputArea;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class PhotoSendBox : public AbstractBox {
|
class SendFilesBox : public AbstractBox {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PhotoSendBox(const FileLoadResultPtr &file);
|
SendFilesBox(const QString &filepath, QImage image, CompressConfirm compressed, bool animated = false);
|
||||||
PhotoSendBox(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo);
|
SendFilesBox(const QStringList &files, CompressConfirm compressed);
|
||||||
|
SendFilesBox(const QString &phone, const QString &firstname, const QString &lastname);
|
||||||
|
|
||||||
|
void setConfirmedCallback(base::lambda<void(const QStringList &files, bool compressed, const QString &caption, bool ctrlShiftEnter)> &&callback) {
|
||||||
|
_confirmedCallback = std_::move(callback);
|
||||||
|
}
|
||||||
|
void setCancelledCallback(base::lambda<void()> &&callback) {
|
||||||
|
_cancelledCallback = std_::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onCompressedChange();
|
void onCompressedChange();
|
||||||
void onCaptionResized();
|
|
||||||
void onSend(bool ctrlShiftEnter = false);
|
void onSend(bool ctrlShiftEnter = false);
|
||||||
|
void onCaptionResized();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void keyPressEvent(QKeyEvent *e) override;
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
@ -50,32 +58,44 @@ protected:
|
||||||
void doSetInnerFocus() override;
|
void doSetInnerFocus() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void setup();
|
||||||
|
void updateTitleText();
|
||||||
void updateBoxSize();
|
void updateBoxSize();
|
||||||
|
void updateControlsGeometry();
|
||||||
|
QString getSendButtonText() const;
|
||||||
|
|
||||||
FileLoadResultPtr _file;
|
QString _titleText;
|
||||||
bool _animated;
|
QStringList _files;
|
||||||
|
const QImage _image;
|
||||||
|
|
||||||
QPixmap _thumb;
|
CompressConfirm _compressConfirm = CompressConfirm::None;
|
||||||
|
bool _animated = false;
|
||||||
|
|
||||||
ChildWidget<Ui::InputArea> _caption;
|
QPixmap _preview;
|
||||||
bool _compressedFromSettings;
|
int _previewLeft = 0;
|
||||||
ChildWidget<Ui::Checkbox> _compressed;
|
int _previewWidth = 0;
|
||||||
|
int _previewHeight = 0;
|
||||||
|
|
||||||
|
QPixmap _fileThumb;
|
||||||
|
Text _nameText;
|
||||||
|
bool _fileIsImage = false;
|
||||||
|
QString _statusText;
|
||||||
|
int _statusWidth = 0;
|
||||||
|
|
||||||
|
QString _contactPhone;
|
||||||
|
QString _contactFirstName;
|
||||||
|
QString _contactLastName;
|
||||||
|
|
||||||
|
base::lambda<void(const QStringList &files, bool compressed, const QString &caption, bool ctrlShiftEnter)> _confirmedCallback;
|
||||||
|
base::lambda<void()> _cancelledCallback;
|
||||||
|
bool _confirmed = false;
|
||||||
|
|
||||||
|
ChildWidget<Ui::InputArea> _caption = { nullptr };
|
||||||
|
ChildWidget<Ui::Checkbox> _compressed = { nullptr };
|
||||||
|
|
||||||
ChildWidget<Ui::RoundButton> _send;
|
ChildWidget<Ui::RoundButton> _send;
|
||||||
ChildWidget<Ui::RoundButton> _cancel;
|
ChildWidget<Ui::RoundButton> _cancel;
|
||||||
|
|
||||||
int32 _thumbx, _thumby, _thumbw, _thumbh;
|
|
||||||
Text _name;
|
|
||||||
QString _status;
|
|
||||||
int32 _statusw;
|
|
||||||
bool _isImage;
|
|
||||||
|
|
||||||
QString _phone, _fname, _lname;
|
|
||||||
|
|
||||||
MsgId _replyTo;
|
|
||||||
|
|
||||||
bool _confirmed;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditCaptionBox : public AbstractBox, public RPCSender {
|
class EditCaptionBox : public AbstractBox, public RPCSender {
|
|
@ -52,7 +52,7 @@ SessionsBox::SessionsBox() : ScrollableBox(st::sessionsScroll)
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
|
|
||||||
MTP::send(MTPaccount_GetAuthorizations(), rpcDone(&SessionsBox::gotAuthorizations));
|
MTP::send(MTPaccount_GetAuthorizations(), rpcDone(&SessionsBox::gotAuthorizations));
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ ShareBox::ShareBox(CopyCallback &©Callback, SubmitCallback &&submitCallback,
|
||||||
|
|
||||||
updateButtonsVisibility();
|
updateButtonsVisibility();
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ShareBox::getTopScrollSkip() const {
|
int ShareBox::getTopScrollSkip() const {
|
||||||
|
|
|
@ -265,7 +265,7 @@ void StickersBox::setup() {
|
||||||
|
|
||||||
rebuildList();
|
rebuildList();
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersBox::refreshTabs() {
|
void StickersBox::refreshTabs() {
|
||||||
|
|
|
@ -63,7 +63,7 @@ StickerSetBox::StickerSetBox(const MTPInputStickerSet &set) : ScrollableBox(st::
|
||||||
|
|
||||||
onScroll();
|
onScroll();
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickerSetBox::onInstalled(uint64 setId) {
|
void StickerSetBox::onInstalled(uint64 setId) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ _about(st::boxWidth - st::usernamePadding.left()) {
|
||||||
|
|
||||||
updateLinkText();
|
updateLinkText();
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsernameBox::doSetInnerFocus() {
|
void UsernameBox::doSetInnerFocus() {
|
||||||
|
|
|
@ -120,7 +120,6 @@ enum {
|
||||||
|
|
||||||
AnimationInMemory = 10 * 1024 * 1024, // 10 Mb gif and mp4 animations held in memory while playing
|
AnimationInMemory = 10 * 1024 * 1024, // 10 Mb gif and mp4 animations held in memory while playing
|
||||||
|
|
||||||
MediaViewImageSizeLimit = 100 * 1024 * 1024, // show up to 100mb jpg/png/gif docs in app
|
|
||||||
MaxZoomLevel = 7, // x8
|
MaxZoomLevel = 7, // x8
|
||||||
ZoomToScreenLevel = 1024, // just constant
|
ZoomToScreenLevel = 1024, // just constant
|
||||||
|
|
||||||
|
@ -351,8 +350,6 @@ enum {
|
||||||
|
|
||||||
DownloadPartSize = 64 * 1024, // 64kb for photo
|
DownloadPartSize = 64 * 1024, // 64kb for photo
|
||||||
DocumentDownloadPartSize = 128 * 1024, // 128kb for document
|
DocumentDownloadPartSize = 128 * 1024, // 128kb for document
|
||||||
MaxUploadPhotoSize = 256 * 1024 * 1024, // 256mb photos max
|
|
||||||
MaxUploadDocumentSize = 1500 * 1024 * 1024, // 1500mb documents max
|
|
||||||
UseBigFilesFrom = 10 * 1024 * 1024, // mtp big files methods used for files greater than 10mb
|
UseBigFilesFrom = 10 * 1024 * 1024, // mtp big files methods used for files greater than 10mb
|
||||||
MaxFileQueries = 16, // max 16 file parts downloaded at the same time
|
MaxFileQueries = 16, // max 16 file parts downloaded at the same time
|
||||||
MaxWebFileQueries = 8, // max 8 http[s] files downloaded at the same time
|
MaxWebFileQueries = 8, // max 8 http[s] files downloaded at the same time
|
||||||
|
|
|
@ -66,9 +66,3 @@ friend Q_DECL_CONSTEXPR QFlags<Flags::enum_type> operator|(Flags::enum_type f1,
|
||||||
Q_DECLARE_FRIEND_INCOMPATIBLE_FLAGS(Flags)
|
Q_DECLARE_FRIEND_INCOMPATIBLE_FLAGS(Flags)
|
||||||
|
|
||||||
#endif // OS_MAC_OLD
|
#endif // OS_MAC_OLD
|
||||||
|
|
||||||
// using for_const instead of plain range-based for loop to ensure usage of const_iterator
|
|
||||||
// it is important for the copy-on-write Qt containers
|
|
||||||
// if you have "QVector<T*> v" then "for (T * const p : v)" will still call QVector::detach(),
|
|
||||||
// while "for_const (T *p, v)" won't and "for_const (T *&p, v)" won't compile
|
|
||||||
#define for_const(range_declaration, range_expression) for (range_declaration : std_::as_const(range_expression))
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
namespace base {
|
namespace base {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <typename Return, typename ...Args>
|
template <typename Return, typename ...Args>
|
||||||
struct lambda_wrap_helper_base {
|
struct lambda_wrap_helper_base {
|
||||||
using construct_copy_other_type = void(*)(void *, const void *); // dst, src
|
using construct_copy_other_type = void(*)(void *, const void *); // dst, src
|
||||||
using construct_move_other_type = void(*)(void *, void *); // dst, src
|
using construct_move_other_type = void(*)(void *, void *); // dst, src
|
||||||
using call_type = Return(*)(const void *, Args...);
|
using call_type = Return(*)(const void *, Args...);
|
||||||
|
@ -59,15 +59,15 @@ struct lambda_wrap_helper_base {
|
||||||
template <typename Lambda>
|
template <typename Lambda>
|
||||||
using IsLarge = std_::integral_constant<bool, !(sizeof(std_::decay_simple_t<Lambda>) <= kStorageSize)>;
|
using IsLarge = std_::integral_constant<bool, !(sizeof(std_::decay_simple_t<Lambda>) <= kStorageSize)>;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void bad_construct_copy(void *lambda, const void *source) {
|
static void bad_construct_copy(void *lambda, const void *source) {
|
||||||
t_assert(!"base::lambda bad_construct_copy() called!");
|
t_assert(!"base::lambda bad_construct_copy() called!");
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Return, typename ...Args>
|
template <typename Return, typename ...Args>
|
||||||
struct lambda_wrap_empty : public lambda_wrap_helper_base<Return, Args...> {
|
struct lambda_wrap_empty : public lambda_wrap_helper_base<Return, Args...> {
|
||||||
static void construct_copy_other_method(void *lambda, const void *source) {
|
static void construct_copy_other_method(void *lambda, const void *source) {
|
||||||
}
|
}
|
||||||
static void construct_move_other_method(void *lambda, void *source) {
|
static void construct_move_other_method(void *lambda, void *source) {
|
||||||
|
@ -87,57 +87,57 @@ struct lambda_wrap_empty : public lambda_wrap_helper_base<Return, Args...> {
|
||||||
|
|
||||||
static const lambda_wrap_empty<Return, Args...> instance;
|
static const lambda_wrap_empty<Return, Args...> instance;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Return, typename ...Args>
|
template <typename Return, typename ...Args>
|
||||||
const lambda_wrap_empty<Return, Args...> lambda_wrap_empty<Return, Args...>::instance = {};
|
const lambda_wrap_empty<Return, Args...> lambda_wrap_empty<Return, Args...>::instance = {};
|
||||||
|
|
||||||
template <typename Lambda, typename IsLarge, typename Return, typename ...Args> struct lambda_wrap_helper_move_impl;
|
template <typename Lambda, typename IsLarge, typename Return, typename ...Args> struct lambda_wrap_helper_move_impl;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Disable large lambda support.
|
// Disable large lambda support.
|
||||||
// If you really need it, just store data in some std_::unique_ptr<struct>.
|
// If you really need it, just store data in some std_::unique_ptr<struct>.
|
||||||
//
|
//
|
||||||
//template <typename Lambda, typename Return, typename ...Args>
|
//template <typename Lambda, typename Return, typename ...Args>
|
||||||
//struct lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> {
|
//struct lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> {
|
||||||
// using JustLambda = std_::decay_simple_t<Lambda>;
|
// using JustLambda = std_::decay_simple_t<Lambda>;
|
||||||
// using LambdaPtr = std_::unique_ptr<JustLambda>;
|
// using LambdaPtr = std_::unique_ptr<JustLambda>;
|
||||||
// using Parent = lambda_wrap_helper_base<Return, Args...>;
|
// using Parent = lambda_wrap_helper_base<Return, Args...>;
|
||||||
// static void construct_move_other_method(void *lambda, void *source) {
|
// static void construct_move_other_method(void *lambda, void *source) {
|
||||||
// auto source_lambda = static_cast<LambdaPtr*>(source);
|
// auto source_lambda = static_cast<LambdaPtr*>(source);
|
||||||
// new (lambda) LambdaPtr(std_::move(*source_lambda));
|
// new (lambda) LambdaPtr(std_::move(*source_lambda));
|
||||||
// }
|
// }
|
||||||
// static void construct_move_lambda_method(void *lambda, void *source) {
|
// static void construct_move_lambda_method(void *lambda, void *source) {
|
||||||
// auto source_lambda = static_cast<JustLambda*>(source);
|
// auto source_lambda = static_cast<JustLambda*>(source);
|
||||||
// new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<JustLambda&&>(*source_lambda)));
|
// new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<JustLambda&&>(*source_lambda)));
|
||||||
// }
|
// }
|
||||||
// static Return call_method(const void *lambda, Args... args) {
|
// static Return call_method(const void *lambda, Args... args) {
|
||||||
// return (**static_cast<const LambdaPtr*>(lambda))(std_::forward<Args>(args)...);
|
// return (**static_cast<const LambdaPtr*>(lambda))(std_::forward<Args>(args)...);
|
||||||
// }
|
// }
|
||||||
// static void destruct_method(const void *lambda) {
|
// static void destruct_method(const void *lambda) {
|
||||||
// static_cast<const LambdaPtr*>(lambda)->~LambdaPtr();
|
// static_cast<const LambdaPtr*>(lambda)->~LambdaPtr();
|
||||||
// }
|
// }
|
||||||
// lambda_wrap_helper_move_impl() : Parent(
|
// lambda_wrap_helper_move_impl() : Parent(
|
||||||
// &Parent::bad_construct_copy,
|
// &Parent::bad_construct_copy,
|
||||||
// &lambda_wrap_helper_move_impl::construct_move_other_method,
|
// &lambda_wrap_helper_move_impl::construct_move_other_method,
|
||||||
// &lambda_wrap_helper_move_impl::call_method,
|
// &lambda_wrap_helper_move_impl::call_method,
|
||||||
// &lambda_wrap_helper_move_impl::destruct_method) {
|
// &lambda_wrap_helper_move_impl::destruct_method) {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
//protected:
|
//protected:
|
||||||
// lambda_wrap_helper_move_impl(
|
// lambda_wrap_helper_move_impl(
|
||||||
// typename Parent::construct_copy_other_type construct_copy_other
|
// typename Parent::construct_copy_other_type construct_copy_other
|
||||||
// ) : Parent(
|
// ) : Parent(
|
||||||
// construct_copy_other,
|
// construct_copy_other,
|
||||||
// &lambda_wrap_helper_move_impl::construct_move_other_method,
|
// &lambda_wrap_helper_move_impl::construct_move_other_method,
|
||||||
// &lambda_wrap_helper_move_impl::call_method,
|
// &lambda_wrap_helper_move_impl::call_method,
|
||||||
// &lambda_wrap_helper_move_impl::destruct_method) {
|
// &lambda_wrap_helper_move_impl::destruct_method) {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
//};
|
//};
|
||||||
|
|
||||||
template <typename Lambda, typename Return, typename ...Args>
|
template <typename Lambda, typename Return, typename ...Args>
|
||||||
struct lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> {
|
struct lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> : public lambda_wrap_helper_base<Return, Args...> {
|
||||||
using JustLambda = std_::decay_simple_t<Lambda>;
|
using JustLambda = std_::decay_simple_t<Lambda>;
|
||||||
using Parent = lambda_wrap_helper_base<Return, Args...>;
|
using Parent = lambda_wrap_helper_base<Return, Args...>;
|
||||||
static void construct_move_other_method(void *lambda, void *source) {
|
static void construct_move_other_method(void *lambda, void *source) {
|
||||||
|
@ -165,7 +165,7 @@ struct lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> :
|
||||||
&lambda_wrap_helper_move_impl::destruct_method) {
|
&lambda_wrap_helper_move_impl::destruct_method) {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
lambda_wrap_helper_move_impl(
|
lambda_wrap_helper_move_impl(
|
||||||
typename Parent::construct_copy_other_type construct_copy_other
|
typename Parent::construct_copy_other_type construct_copy_other
|
||||||
) : Parent(
|
) : Parent(
|
||||||
|
@ -175,44 +175,44 @@ protected:
|
||||||
&lambda_wrap_helper_move_impl::destruct_method) {
|
&lambda_wrap_helper_move_impl::destruct_method) {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Lambda, typename Return, typename ...Args>
|
template <typename Lambda, typename Return, typename ...Args>
|
||||||
struct lambda_wrap_helper_move : public lambda_wrap_helper_move_impl<Lambda
|
struct lambda_wrap_helper_move : public lambda_wrap_helper_move_impl<Lambda
|
||||||
, typename lambda_wrap_helper_base<Return, Args...>::template IsLarge<Lambda>
|
, typename lambda_wrap_helper_base<Return, Args...>::template IsLarge<Lambda>
|
||||||
, Return, Args...> {
|
, Return, Args...> {
|
||||||
static const lambda_wrap_helper_move instance;
|
static const lambda_wrap_helper_move instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Lambda, typename Return, typename ...Args>
|
template <typename Lambda, typename Return, typename ...Args>
|
||||||
const lambda_wrap_helper_move<Lambda, Return, Args...> lambda_wrap_helper_move<Lambda, Return, Args...>::instance = {};
|
const lambda_wrap_helper_move<Lambda, Return, Args...> lambda_wrap_helper_move<Lambda, Return, Args...>::instance = {};
|
||||||
|
|
||||||
template <typename Lambda, typename IsLarge, typename Return, typename ...Args> struct lambda_wrap_helper_copy_impl;
|
template <typename Lambda, typename IsLarge, typename Return, typename ...Args> struct lambda_wrap_helper_copy_impl;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Disable large lambda support.
|
// Disable large lambda support.
|
||||||
// If you really need it, just store data in some QSharedPointer<struct>.
|
// If you really need it, just store data in some QSharedPointer<struct>.
|
||||||
//
|
//
|
||||||
//template <typename Lambda, typename Return, typename ...Args>
|
//template <typename Lambda, typename Return, typename ...Args>
|
||||||
//struct lambda_wrap_helper_copy_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> {
|
//struct lambda_wrap_helper_copy_impl<Lambda, std_::true_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...> {
|
||||||
// using JustLambda = std_::decay_simple_t<Lambda>;
|
// using JustLambda = std_::decay_simple_t<Lambda>;
|
||||||
// using LambdaPtr = std_::unique_ptr<JustLambda>;
|
// using LambdaPtr = std_::unique_ptr<JustLambda>;
|
||||||
// using Parent = lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...>;
|
// using Parent = lambda_wrap_helper_move_impl<Lambda, std_::true_type, Return, Args...>;
|
||||||
// static void construct_copy_other_method(void *lambda, const void *source) {
|
// static void construct_copy_other_method(void *lambda, const void *source) {
|
||||||
// auto source_lambda = static_cast<const LambdaPtr*>(source);
|
// auto source_lambda = static_cast<const LambdaPtr*>(source);
|
||||||
// new (lambda) LambdaPtr(std_::make_unique<JustLambda>(*source_lambda->get()));
|
// new (lambda) LambdaPtr(std_::make_unique<JustLambda>(*source_lambda->get()));
|
||||||
// }
|
// }
|
||||||
// static void construct_copy_lambda_method(void *lambda, const void *source) {
|
// static void construct_copy_lambda_method(void *lambda, const void *source) {
|
||||||
// auto source_lambda = static_cast<const JustLambda*>(source);
|
// auto source_lambda = static_cast<const JustLambda*>(source);
|
||||||
// new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<const JustLambda &>(*source_lambda)));
|
// new (lambda) LambdaPtr(std_::make_unique<JustLambda>(static_cast<const JustLambda &>(*source_lambda)));
|
||||||
// }
|
// }
|
||||||
// lambda_wrap_helper_copy_impl() : Parent(&lambda_wrap_helper_copy_impl::construct_copy_other_method) {
|
// lambda_wrap_helper_copy_impl() : Parent(&lambda_wrap_helper_copy_impl::construct_copy_other_method) {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
//};
|
//};
|
||||||
|
|
||||||
template <typename Lambda, typename Return, typename ...Args>
|
template <typename Lambda, typename Return, typename ...Args>
|
||||||
struct lambda_wrap_helper_copy_impl<Lambda, std_::false_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> {
|
struct lambda_wrap_helper_copy_impl<Lambda, std_::false_type, Return, Args...> : public lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...> {
|
||||||
using JustLambda = std_::decay_simple_t<Lambda>;
|
using JustLambda = std_::decay_simple_t<Lambda>;
|
||||||
using Parent = lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...>;
|
using Parent = lambda_wrap_helper_move_impl<Lambda, std_::false_type, Return, Args...>;
|
||||||
static void construct_copy_other_method(void *lambda, const void *source) {
|
static void construct_copy_other_method(void *lambda, const void *source) {
|
||||||
|
@ -230,17 +230,17 @@ struct lambda_wrap_helper_copy_impl<Lambda, std_::false_type, Return, Args...> :
|
||||||
lambda_wrap_helper_copy_impl() : Parent(&lambda_wrap_helper_copy_impl::construct_copy_other_method) {
|
lambda_wrap_helper_copy_impl() : Parent(&lambda_wrap_helper_copy_impl::construct_copy_other_method) {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Lambda, typename Return, typename ...Args>
|
template <typename Lambda, typename Return, typename ...Args>
|
||||||
struct lambda_wrap_helper_copy : public lambda_wrap_helper_copy_impl<Lambda
|
struct lambda_wrap_helper_copy : public lambda_wrap_helper_copy_impl<Lambda
|
||||||
, typename lambda_wrap_helper_base<Return, Args...>::template IsLarge<Lambda>
|
, typename lambda_wrap_helper_base<Return, Args...>::template IsLarge<Lambda>
|
||||||
, Return, Args...> {
|
, Return, Args...> {
|
||||||
static const lambda_wrap_helper_copy instance;
|
static const lambda_wrap_helper_copy instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Lambda, typename Return, typename ...Args>
|
template <typename Lambda, typename Return, typename ...Args>
|
||||||
const lambda_wrap_helper_copy<Lambda, Return, Args...> lambda_wrap_helper_copy<Lambda, Return, Args...>::instance = {};
|
const lambda_wrap_helper_copy<Lambda, Return, Args...> lambda_wrap_helper_copy<Lambda, Return, Args...>::instance = {};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
@ -262,6 +262,8 @@ class lambda<Return(Args...)> {
|
||||||
using IsRvalue = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>;
|
using IsRvalue = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using return_type = Return;
|
||||||
|
|
||||||
lambda() : helper_(&EmptyHelper::instance) {
|
lambda() : helper_(&EmptyHelper::instance) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,6 +389,116 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Get lambda type from a lambda template parameter.
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <typename FunctionType>
|
||||||
|
struct lambda_type_helper;
|
||||||
|
|
||||||
|
template <typename Lambda, typename R, typename ...Args>
|
||||||
|
struct lambda_type_helper<R(Lambda::*)(Args...) const> {
|
||||||
|
using type = lambda<R(Args...)>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename FunctionType>
|
||||||
|
using lambda_type = typename internal::lambda_type_helper<decltype(&FunctionType::operator())>::type;
|
||||||
|
|
||||||
|
// Guard lambda call by one or many QObject* weak pointers.
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
class lambda_guard_creator;
|
||||||
|
|
||||||
|
template <int N, typename Lambda>
|
||||||
|
class lambda_guard_data {
|
||||||
|
public:
|
||||||
|
using return_type = typename lambda_type<Lambda>::return_type;
|
||||||
|
|
||||||
|
template <typename ...PointersAndLambda>
|
||||||
|
lambda_guard_data(PointersAndLambda&&... qobjectsAndLambda) : _lambda(init(_pointers, std_::forward<PointersAndLambda>(qobjectsAndLambda)...)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ...Args>
|
||||||
|
inline return_type operator()(Args... args) const {
|
||||||
|
for (int i = 0; i != N; ++i) {
|
||||||
|
if (!_pointers[i]) {
|
||||||
|
return return_type();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _lambda(std_::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename ...PointersAndLambda>
|
||||||
|
Lambda init(QPointer<QObject> *pointers, QObject *qobject, PointersAndLambda&&... qobjectsAndLambda) {
|
||||||
|
*pointers = qobject;
|
||||||
|
return init(++pointers, std_::forward<PointersAndLambda>(qobjectsAndLambda)...);
|
||||||
|
}
|
||||||
|
Lambda init(QPointer<QObject> *pointers, Lambda &&lambda) {
|
||||||
|
return std_::move(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointer<QObject> _pointers[N];
|
||||||
|
Lambda _lambda;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <int N, typename Lambda>
|
||||||
|
class lambda_guard {
|
||||||
|
public:
|
||||||
|
using return_type = typename lambda_type<Lambda>::return_type;
|
||||||
|
|
||||||
|
template <typename ...PointersAndLambda>
|
||||||
|
lambda_guard(PointersAndLambda&&... qobjectsAndLambda) : _data(std_::make_unique<lambda_guard_data<N, Lambda>>(std_::forward<PointersAndLambda>(qobjectsAndLambda)...)) {
|
||||||
|
static_assert(sizeof...(PointersAndLambda) == N + 1, "Wrong argument count!");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ...Args>
|
||||||
|
inline return_type operator()(Args... args) const {
|
||||||
|
return (*_data)(std_::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std_::unique_ptr<lambda_guard_data<N, Lambda>> _data;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <int N, int K, typename ...PointersAndLambda>
|
||||||
|
struct lambda_guard_type;
|
||||||
|
|
||||||
|
template <int N, int K, typename Pointer, typename ...PointersAndLambda>
|
||||||
|
struct lambda_guard_type<N, K, Pointer, PointersAndLambda...> {
|
||||||
|
using type = typename lambda_guard_type<N, K - 1, PointersAndLambda...>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <int N, typename Lambda>
|
||||||
|
struct lambda_guard_type<N, 0, Lambda> {
|
||||||
|
using type = lambda_guard<N, Lambda>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ...PointersAndLambda>
|
||||||
|
struct lambda_guard_type_helper {
|
||||||
|
static constexpr int N = sizeof...(PointersAndLambda);
|
||||||
|
using type = typename lambda_guard_type<N - 1, N - 1, PointersAndLambda...>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ...PointersAndLambda>
|
||||||
|
using lambda_guard_t = typename lambda_guard_type_helper<PointersAndLambda...>::type;
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename ...PointersAndLambda>
|
||||||
|
inline internal::lambda_guard_t<PointersAndLambda...> lambda_guarded(PointersAndLambda&&... qobjectsAndLambda) {
|
||||||
|
static_assert(sizeof...(PointersAndLambda) > 0, "Lambda should be passed here.");
|
||||||
|
return internal::lambda_guard_t<PointersAndLambda...>(std_::forward<PointersAndLambda>(qobjectsAndLambda)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass lambda instead of a Qt void() slot.
|
||||||
|
|
||||||
class lambda_slot_wrap : public QObject {
|
class lambda_slot_wrap : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ public:
|
||||||
if (!_data) {
|
if (!_data) {
|
||||||
_data = MakeShared<ObservableData<EventType, Handler>>(this);
|
_data = MakeShared<ObservableData<EventType, Handler>>(this);
|
||||||
}
|
}
|
||||||
return _data->append(std_::forward<Handler>(handler));
|
return _data->append(std_::move(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -169,7 +169,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Subscription append(Handler &&handler) {
|
Subscription append(Handler &&handler) {
|
||||||
auto node = new Node(_observable->_data, std_::forward<Handler>(handler));
|
auto node = new Node(_observable->_data, std_::move(handler));
|
||||||
if (_begin) {
|
if (_begin) {
|
||||||
_end->next = node;
|
_end->next = node;
|
||||||
node->prev = _end;
|
node->prev = _end;
|
||||||
|
|
|
@ -158,14 +158,9 @@ template <typename T>
|
||||||
struct add_const {
|
struct add_const {
|
||||||
using type = const T;
|
using type = const T;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using add_const_t = typename add_const<T>::type;
|
using add_const_t = typename add_const<T>::type;
|
||||||
template <typename T>
|
|
||||||
constexpr add_const_t<T> &as_const(T& t) noexcept {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
template <typename T>
|
|
||||||
void as_const(const T&&) = delete;
|
|
||||||
|
|
||||||
// This is not full unique_ptr, but at least with std interface.
|
// This is not full unique_ptr, but at least with std interface.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -47,6 +47,11 @@ inline constexpr D up_cast_helper(std_::false_type, T object) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr std_::add_const_t<T> &any_as_const(T &&value) noexcept {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
template <typename D, typename T>
|
template <typename D, typename T>
|
||||||
|
@ -83,6 +88,12 @@ scope_guard_helper<Lambda> scope_guard(Lambda on_scope_exit) {
|
||||||
|
|
||||||
} // namespace base
|
} // namespace base
|
||||||
|
|
||||||
|
// using for_const instead of plain range-based for loop to ensure usage of const_iterator
|
||||||
|
// it is important for the copy-on-write Qt containers
|
||||||
|
// if you have "QVector<T*> v" then "for (T * const p : v)" will still call QVector::detach(),
|
||||||
|
// while "for_const (T *p, v)" won't and "for_const (T *&p, v)" won't compile
|
||||||
|
#define for_const(range_declaration, range_expression) for (range_declaration : base::internal::any_as_const(range_expression))
|
||||||
|
|
||||||
template <typename Enum>
|
template <typename Enum>
|
||||||
inline QFlags<Enum> qFlags(Enum v) {
|
inline QFlags<Enum> qFlags(Enum v) {
|
||||||
return QFlags<Enum>(v);
|
return QFlags<Enum>(v);
|
||||||
|
@ -352,11 +363,6 @@ enum DBIConnectionType {
|
||||||
dbictTcpProxy = 3,
|
dbictTcpProxy = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DBIDefaultAttach {
|
|
||||||
dbidaDocument = 0,
|
|
||||||
dbidaPhoto = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ProxyData {
|
struct ProxyData {
|
||||||
QString host;
|
QString host;
|
||||||
uint32 port = 0;
|
uint32 port = 0;
|
||||||
|
|
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "core/utils.h"
|
#include "core/utils.h"
|
||||||
|
|
||||||
#define BETA_VERSION_MACRO (10019009ULL)
|
#define BETA_VERSION_MACRO (10019010ULL)
|
||||||
|
|
||||||
constexpr int AppVersion = 10020;
|
constexpr int AppVersion = 10020;
|
||||||
constexpr str_const AppVersionStr = "0.10.20";
|
constexpr str_const AppVersionStr = "0.10.20";
|
||||||
|
|
|
@ -29,10 +29,10 @@ FileUploader::FileUploader() : sentSize(0) {
|
||||||
connect(&killSessionsTimer, SIGNAL(timeout()), this, SLOT(killSessions()));
|
connect(&killSessionsTimer, SIGNAL(timeout()), this, SLOT(killSessions()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &media) {
|
void FileUploader::uploadMedia(const FullMsgId &msgId, const SendMediaReady &media) {
|
||||||
if (media.type == PreparePhoto) {
|
if (media.type == SendMediaType::Photo) {
|
||||||
App::feedPhoto(media.photo, media.photoThumbs);
|
App::feedPhoto(media.photo, media.photoThumbs);
|
||||||
} else if (media.type == PrepareDocument || media.type == PrepareAudio) {
|
} else if (media.type == SendMediaType::File || media.type == SendMediaType::Audio) {
|
||||||
DocumentData *document;
|
DocumentData *document;
|
||||||
if (media.photoThumbs.isEmpty()) {
|
if (media.photoThumbs.isEmpty()) {
|
||||||
document = App::feedDocument(media.document);
|
document = App::feedDocument(media.document);
|
||||||
|
@ -52,10 +52,10 @@ void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &me
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file) {
|
void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file) {
|
||||||
if (file->type == PreparePhoto) {
|
if (file->type == SendMediaType::Photo) {
|
||||||
PhotoData *photo = App::feedPhoto(file->photo, file->photoThumbs);
|
PhotoData *photo = App::feedPhoto(file->photo, file->photoThumbs);
|
||||||
photo->uploadingData = new PhotoData::UploadingData(file->partssize);
|
photo->uploadingData = new PhotoData::UploadingData(file->partssize);
|
||||||
} else if (file->type == PrepareDocument || file->type == PrepareAudio) {
|
} else if (file->type == SendMediaType::File || file->type == SendMediaType::Audio) {
|
||||||
DocumentData *document;
|
DocumentData *document;
|
||||||
if (file->thumb.isNull()) {
|
if (file->thumb.isNull()) {
|
||||||
document = App::feedDocument(file->document);
|
document = App::feedDocument(file->document);
|
||||||
|
@ -77,9 +77,9 @@ void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file)
|
||||||
void FileUploader::currentFailed() {
|
void FileUploader::currentFailed() {
|
||||||
Queue::iterator j = queue.find(uploading);
|
Queue::iterator j = queue.find(uploading);
|
||||||
if (j != queue.end()) {
|
if (j != queue.end()) {
|
||||||
if (j->type() == PreparePhoto) {
|
if (j->type() == SendMediaType::Photo) {
|
||||||
emit photoFailed(j.key());
|
emit photoFailed(j.key());
|
||||||
} else if (j->type() == PrepareDocument) {
|
} else if (j->type() == SendMediaType::File) {
|
||||||
DocumentData *doc = App::document(j->id());
|
DocumentData *doc = App::document(j->id());
|
||||||
if (doc->status == FileUploading) {
|
if (doc->status == FileUploading) {
|
||||||
doc->status = FileUploadFailed;
|
doc->status = FileUploadFailed;
|
||||||
|
@ -135,15 +135,15 @@ void FileUploader::sendNext() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UploadFileParts &parts(i->file ? (i->type() == PreparePhoto ? i->file->fileparts : i->file->thumbparts) : i->media.parts);
|
UploadFileParts &parts(i->file ? (i->type() == SendMediaType::Photo ? i->file->fileparts : i->file->thumbparts) : i->media.parts);
|
||||||
uint64 partsOfId(i->file ? (i->type() == PreparePhoto ? i->file->id : i->file->thumbId) : i->media.thumbId);
|
uint64 partsOfId(i->file ? (i->type() == SendMediaType::Photo ? i->file->id : i->file->thumbId) : i->media.thumbId);
|
||||||
if (parts.isEmpty()) {
|
if (parts.isEmpty()) {
|
||||||
if (i->docSentParts >= i->docPartsCount) {
|
if (i->docSentParts >= i->docPartsCount) {
|
||||||
if (requestsSent.isEmpty() && docRequestsSent.isEmpty()) {
|
if (requestsSent.isEmpty() && docRequestsSent.isEmpty()) {
|
||||||
bool silent = i->file && i->file->to.silent;
|
bool silent = i->file && i->file->to.silent;
|
||||||
if (i->type() == PreparePhoto) {
|
if (i->type() == SendMediaType::Photo) {
|
||||||
emit photoReady(uploading, silent, MTP_inputFile(MTP_long(i->id()), MTP_int(i->partsCount), MTP_string(i->filename()), MTP_bytes(i->file ? i->file->filemd5 : i->media.jpeg_md5)));
|
emit photoReady(uploading, silent, MTP_inputFile(MTP_long(i->id()), MTP_int(i->partsCount), MTP_string(i->filename()), MTP_bytes(i->file ? i->file->filemd5 : i->media.jpeg_md5)));
|
||||||
} else if (i->type() == PrepareDocument || i->type() == PrepareAudio) {
|
} else if (i->type() == SendMediaType::File || i->type() == SendMediaType::Audio) {
|
||||||
QByteArray docMd5(32, Qt::Uninitialized);
|
QByteArray docMd5(32, Qt::Uninitialized);
|
||||||
hashMd5Hex(i->md5Hash.result(), docMd5.data());
|
hashMd5Hex(i->md5Hash.result(), docMd5.data());
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ void FileUploader::sendNext() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
toSend = content.mid(i->docSentParts * i->docPartSize, i->docPartSize);
|
toSend = content.mid(i->docSentParts * i->docPartSize, i->docPartSize);
|
||||||
if ((i->type() == PrepareDocument || i->type() == PrepareAudio) && i->docSentParts <= UseBigFilesFrom) {
|
if ((i->type() == SendMediaType::File || i->type() == SendMediaType::Audio) && i->docSentParts <= UseBigFilesFrom) {
|
||||||
i->md5Hash.feed(toSend.constData(), toSend.size());
|
i->md5Hash.feed(toSend.constData(), toSend.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
|
||||||
}
|
}
|
||||||
sentSize -= sentPartSize;
|
sentSize -= sentPartSize;
|
||||||
sentSizes[dc] -= sentPartSize;
|
sentSizes[dc] -= sentPartSize;
|
||||||
if (k->type() == PreparePhoto) {
|
if (k->type() == SendMediaType::Photo) {
|
||||||
k->fileSentSize += sentPartSize;
|
k->fileSentSize += sentPartSize;
|
||||||
PhotoData *photo = App::photo(k->id());
|
PhotoData *photo = App::photo(k->id());
|
||||||
if (photo->uploading() && k->file) {
|
if (photo->uploading() && k->file) {
|
||||||
|
@ -290,7 +290,7 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
|
||||||
photo->uploadingData->offset = k->fileSentSize;
|
photo->uploadingData->offset = k->fileSentSize;
|
||||||
}
|
}
|
||||||
emit photoProgress(k.key());
|
emit photoProgress(k.key());
|
||||||
} else if (k->type() == PrepareDocument || k->type() == PrepareAudio) {
|
} else if (k->type() == SendMediaType::File || k->type() == SendMediaType::Audio) {
|
||||||
DocumentData *doc = App::document(k->id());
|
DocumentData *doc = App::document(k->id());
|
||||||
if (doc->uploading()) {
|
if (doc->uploading()) {
|
||||||
doc->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
|
doc->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
|
||||||
|
|
|
@ -26,9 +26,8 @@ class FileUploader : public QObject, public RPCSender {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FileUploader();
|
FileUploader();
|
||||||
void uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &image);
|
void uploadMedia(const FullMsgId &msgId, const SendMediaReady &image);
|
||||||
void upload(const FullMsgId &msgId, const FileLoadResultPtr &file);
|
void upload(const FullMsgId &msgId, const FileLoadResultPtr &file);
|
||||||
|
|
||||||
int32 currentOffset(const FullMsgId &msgId) const; // -1 means file not found
|
int32 currentOffset(const FullMsgId &msgId) const; // -1 means file not found
|
||||||
|
@ -41,13 +40,11 @@ public:
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void unpause();
|
void unpause();
|
||||||
void sendNext();
|
void sendNext();
|
||||||
void killSessions();
|
void killSessions();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void photoReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
|
void photoReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
|
||||||
void documentReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
|
void documentReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
|
||||||
void thumbDocumentReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file, const MTPInputFile &thumb);
|
void thumbDocumentReady(const FullMsgId &msgId, bool silent, const MTPInputFile &file, const MTPInputFile &thumb);
|
||||||
|
@ -59,19 +56,18 @@ signals:
|
||||||
void documentFailed(const FullMsgId &msgId);
|
void documentFailed(const FullMsgId &msgId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct File {
|
struct File {
|
||||||
File(const ReadyLocalMedia &media) : media(media), docSentParts(0) {
|
File(const SendMediaReady &media) : media(media), docSentParts(0) {
|
||||||
partsCount = media.parts.size();
|
partsCount = media.parts.size();
|
||||||
if (type() == PrepareDocument || type() == PrepareAudio) {
|
if (type() == SendMediaType::File || type() == SendMediaType::Audio) {
|
||||||
setDocSize(media.file.isEmpty() ? media.data.size() : media.filesize);
|
setDocSize(media.file.isEmpty() ? media.data.size() : media.filesize);
|
||||||
} else {
|
} else {
|
||||||
docSize = docPartSize = docPartsCount = 0;
|
docSize = docPartSize = docPartsCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File(const FileLoadResultPtr &file) : file(file), docSentParts(0) {
|
File(const FileLoadResultPtr &file) : file(file), docSentParts(0) {
|
||||||
partsCount = (type() == PreparePhoto) ? file->fileparts.size() : file->thumbparts.size();
|
partsCount = (type() == SendMediaType::Photo) ? file->fileparts.size() : file->thumbparts.size();
|
||||||
if (type() == PrepareDocument || type() == PrepareAudio) {
|
if (type() == SendMediaType::File || type() == SendMediaType::Audio) {
|
||||||
setDocSize(file->filesize);
|
setDocSize(file->filesize);
|
||||||
} else {
|
} else {
|
||||||
docSize = docPartSize = docPartsCount = 0;
|
docSize = docPartSize = docPartsCount = 0;
|
||||||
|
@ -98,14 +94,14 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLoadResultPtr file;
|
FileLoadResultPtr file;
|
||||||
ReadyLocalMedia media;
|
SendMediaReady media;
|
||||||
int32 partsCount;
|
int32 partsCount;
|
||||||
mutable int32 fileSentSize;
|
mutable int32 fileSentSize;
|
||||||
|
|
||||||
uint64 id() const {
|
uint64 id() const {
|
||||||
return file ? file->id : media.id;
|
return file ? file->id : media.id;
|
||||||
}
|
}
|
||||||
PrepareMediaType type() const {
|
SendMediaType type() const {
|
||||||
return file ? file->type : media.type;
|
return file ? file->type : media.type;
|
||||||
}
|
}
|
||||||
uint64 thumbId() const {
|
uint64 thumbId() const {
|
||||||
|
|
|
@ -235,10 +235,6 @@ historyAttach: IconButton(historySend) {
|
||||||
color: windowBgOver;
|
color: windowBgOver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
historyAttachFileIcon: icon {{ "media_type_file", historyComposeIconFg }};
|
|
||||||
historyAttachFileIconOver: icon {{ "media_type_file", historyComposeIconFgOver }};
|
|
||||||
historyAttachPhotoIcon: icon {{ "media_type_photo", historyComposeIconFg }};
|
|
||||||
historyAttachPhotoIconOver: icon {{ "media_type_photo", historyComposeIconFgOver }};
|
|
||||||
|
|
||||||
historyAttachEmoji: IconButton(historyAttach) {
|
historyAttachEmoji: IconButton(historyAttach) {
|
||||||
icon: icon {{ "send_control_emoji", historyComposeIconFg }};
|
icon: icon {{ "send_control_emoji", historyComposeIconFg }};
|
||||||
|
@ -283,17 +279,6 @@ historyRecordFont: font(13px);
|
||||||
historyRecordDurationFg: #000000;
|
historyRecordDurationFg: #000000;
|
||||||
historyRecordTextTop: 14px;
|
historyRecordTextTop: 14px;
|
||||||
|
|
||||||
historyAttachDropdownMenu: DropdownMenu(defaultDropdownMenu) {
|
|
||||||
menu: Menu(defaultMenu) {
|
|
||||||
itemIconPosition: point(13px, 6px);
|
|
||||||
itemPadding: margins(54px, 11px, 54px, 11px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
historyMediaTypeFile: icon {{ "media_type_file", menuIconFg, point(2px, 2px) }};
|
|
||||||
historyMediaTypeFileOver: icon {{ "media_type_file", menuIconFgOver, point(2px, 2px) }};
|
|
||||||
historyMediaTypePhoto: icon {{ "media_type_photo", menuIconFg, point(2px, 2px) }};
|
|
||||||
historyMediaTypePhotoOver: icon {{ "media_type_photo", menuIconFgOver, point(2px, 2px) }};
|
|
||||||
|
|
||||||
historySilentToggle: IconButton(historyBotKeyboardShow) {
|
historySilentToggle: IconButton(historyBotKeyboardShow) {
|
||||||
icon: icon {{ "send_control_silent_off", historyComposeIconFg }};
|
icon: icon {{ "send_control_silent_off", historyComposeIconFg }};
|
||||||
iconOver: icon {{ "send_control_silent_off", historyComposeIconFgOver }};
|
iconOver: icon {{ "send_control_silent_off", historyComposeIconFgOver }};
|
||||||
|
|
|
@ -116,8 +116,8 @@ void DragArea::dragLeaveEvent(QDragLeaveEvent *e) {
|
||||||
|
|
||||||
void DragArea::dropEvent(QDropEvent *e) {
|
void DragArea::dropEvent(QDropEvent *e) {
|
||||||
static_cast<HistoryWidget*>(parentWidget())->dropEvent(e);
|
static_cast<HistoryWidget*>(parentWidget())->dropEvent(e);
|
||||||
if (e->isAccepted()) {
|
if (e->isAccepted() && _droppedCallback) {
|
||||||
emit dropped(e->mimeData());
|
_droppedCallback(e->mimeData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,10 @@ public:
|
||||||
|
|
||||||
void hideFast();
|
void hideFast();
|
||||||
|
|
||||||
|
void setDroppedCallback(base::lambda<void(const QMimeData *data)> &&callback) {
|
||||||
|
_droppedCallback = std_::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
@ -56,9 +60,6 @@ protected:
|
||||||
void dropEvent(QDropEvent *e) override;
|
void dropEvent(QDropEvent *e) override;
|
||||||
void dragMoveEvent(QDragMoveEvent *e) override;
|
void dragMoveEvent(QDragMoveEvent *e) override;
|
||||||
|
|
||||||
signals:
|
|
||||||
void dropped(const QMimeData *data);
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void hideStart();
|
void hideStart();
|
||||||
void hideFinish();
|
void hideFinish();
|
||||||
|
@ -67,6 +68,7 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _hiding, _in;
|
bool _hiding, _in;
|
||||||
|
base::lambda<void(const QMimeData *data)> _droppedCallback;
|
||||||
|
|
||||||
anim::fvalue a_opacity;
|
anim::fvalue a_opacity;
|
||||||
anim::fvalue a_colorDrop;
|
anim::fvalue a_colorDrop;
|
||||||
|
|
|
@ -99,7 +99,7 @@ QString ReplyMarkupClickHandler::buttonText() const {
|
||||||
ReplyKeyboard::ReplyKeyboard(const HistoryItem *item, StylePtr &&s)
|
ReplyKeyboard::ReplyKeyboard(const HistoryItem *item, StylePtr &&s)
|
||||||
: _item(item)
|
: _item(item)
|
||||||
, _a_selected(animation(this, &ReplyKeyboard::step_selected))
|
, _a_selected(animation(this, &ReplyKeyboard::step_selected))
|
||||||
, _st(std_::forward<StylePtr>(s)) {
|
, _st(std_::move(s)) {
|
||||||
if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
|
if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
|
||||||
_rows.reserve(markup->rows.size());
|
_rows.reserve(markup->rows.size());
|
||||||
for (int i = 0, l = markup->rows.size(); i != l; ++i) {
|
for (int i = 0, l = markup->rows.size(); i != l; ++i) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "styles/style_window.h"
|
#include "styles/style_window.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "boxes/photosendbox.h"
|
#include "boxes/send_files_box.h"
|
||||||
#include "boxes/sharebox.h"
|
#include "boxes/sharebox.h"
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
|
@ -57,6 +57,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "observer_peer.h"
|
#include "observer_peer.h"
|
||||||
#include "core/qthelp_regex.h"
|
#include "core/qthelp_regex.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
#include "platform/platform_file_dialog.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -2392,29 +2393,9 @@ bool MessageField::canInsertFromMimeData(const QMimeData *source) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageField::insertFromMimeData(const QMimeData *source) {
|
void MessageField::insertFromMimeData(const QMimeData *source) {
|
||||||
if (source->hasUrls()) {
|
if (history->confirmSendingFiles(source, CompressConfirm::Auto, source->text())) {
|
||||||
int32 files = 0;
|
|
||||||
QUrl url;
|
|
||||||
for (int32 i = 0; i < source->urls().size(); ++i) {
|
|
||||||
if (source->urls().at(i).isLocalFile()) {
|
|
||||||
url = source->urls().at(i);
|
|
||||||
++files;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (files == 1) {
|
|
||||||
history->uploadFile(url.toLocalFile(), PrepareAuto, FileLoadAlwaysConfirm);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (files > 1) return;
|
|
||||||
//if (files > 1) return uploadFiles(files, PrepareAuto); // multiple confirm with "compressed" checkbox
|
|
||||||
}
|
|
||||||
if (source->hasImage()) {
|
|
||||||
QImage img = qvariant_cast<QImage>(source->imageData());
|
|
||||||
if (!img.isNull()) {
|
|
||||||
history->uploadImage(img, PrepareAuto, FileLoadAlwaysConfirm, source->text());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FlatTextarea::insertFromMimeData(source);
|
FlatTextarea::insertFromMimeData(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2896,33 +2877,30 @@ bool HistoryHider::offerPeer(PeerId peer) {
|
||||||
if (_sharedContact) {
|
if (_sharedContact) {
|
||||||
phrase = lng_forward_share_contact(lt_recipient, recipient);
|
phrase = lng_forward_share_contact(lt_recipient, recipient);
|
||||||
} else if (_sendPath) {
|
} else if (_sendPath) {
|
||||||
if (cSendPaths().size() > 1) {
|
auto toId = _offered->id;
|
||||||
phrase = lng_forward_send_files_confirm(lt_recipient, recipient);
|
|
||||||
} else {
|
|
||||||
QString name(QFileInfo(cSendPaths().front()).fileName());
|
|
||||||
if (name.size() > 10) {
|
|
||||||
name = name.mid(0, 8) + '.' + '.';
|
|
||||||
}
|
|
||||||
phrase = lng_forward_send_file_confirm(lt_name, name, lt_recipient, recipient);
|
|
||||||
}
|
|
||||||
} else if (!_shareUrl.isEmpty()) {
|
|
||||||
PeerId to = _offered->id;
|
|
||||||
_offered = nullptr;
|
_offered = nullptr;
|
||||||
if (parent()->onShareUrl(to, _shareUrl, _shareText)) {
|
if (parent()->onSendPaths(toId)) {
|
||||||
|
startHide();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (!_shareUrl.isEmpty()) {
|
||||||
|
auto toId = _offered->id;
|
||||||
|
_offered = nullptr;
|
||||||
|
if (parent()->onShareUrl(toId, _shareUrl, _shareText)) {
|
||||||
startHide();
|
startHide();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else if (!_botAndQuery.isEmpty()) {
|
} else if (!_botAndQuery.isEmpty()) {
|
||||||
PeerId to = _offered->id;
|
auto toId = _offered->id;
|
||||||
_offered = nullptr;
|
_offered = nullptr;
|
||||||
if (parent()->onInlineSwitchChosen(to, _botAndQuery)) {
|
if (parent()->onInlineSwitchChosen(toId, _botAndQuery)) {
|
||||||
startHide();
|
startHide();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
PeerId to = _offered->id;
|
auto toId = _offered->id;
|
||||||
_offered = nullptr;
|
_offered = nullptr;
|
||||||
if (parent()->onForward(to, _forwardSelected ? ForwardSelectedMessages : ForwardContextMessage)) {
|
if (parent()->onForward(toId, _forwardSelected ? ForwardSelectedMessages : ForwardContextMessage)) {
|
||||||
startHide();
|
startHide();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -3079,7 +3057,6 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
||||||
, _recordCancelWidth(st::historyRecordFont->width(lang(lng_record_cancel)))
|
, _recordCancelWidth(st::historyRecordFont->width(lang(lng_record_cancel)))
|
||||||
, _kbScroll(this, st::botKbScroll)
|
, _kbScroll(this, st::botKbScroll)
|
||||||
, _keyboard(this)
|
, _keyboard(this)
|
||||||
, _attachType(this, st::historyAttachDropdownMenu)
|
|
||||||
, _emojiPan(this)
|
, _emojiPan(this)
|
||||||
, _attachDragDocument(this)
|
, _attachDragDocument(this)
|
||||||
, _attachDragPhoto(this)
|
, _attachDragPhoto(this)
|
||||||
|
@ -3101,18 +3078,6 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
||||||
connect(_joinChannel, SIGNAL(clicked()), this, SLOT(onJoinChannel()));
|
connect(_joinChannel, SIGNAL(clicked()), this, SLOT(onJoinChannel()));
|
||||||
connect(_muteUnmute, SIGNAL(clicked()), this, SLOT(onMuteUnmute()));
|
connect(_muteUnmute, SIGNAL(clicked()), this, SLOT(onMuteUnmute()));
|
||||||
connect(_silent, SIGNAL(clicked()), this, SLOT(onBroadcastSilentChange()));
|
connect(_silent, SIGNAL(clicked()), this, SLOT(onBroadcastSilentChange()));
|
||||||
_attachToggle->setClickedCallback([this] {
|
|
||||||
if (cDefaultAttach() == dbidaPhoto) {
|
|
||||||
onPhotoSelect();
|
|
||||||
} else {
|
|
||||||
onDocumentSelect();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (cDefaultAttach() == dbidaPhoto) {
|
|
||||||
_attachToggle->setIcon(&st::historyAttachPhotoIcon, &st::historyAttachPhotoIconOver);
|
|
||||||
} else {
|
|
||||||
_attachToggle->setIcon(&st::historyAttachFileIcon, &st::historyAttachFileIconOver);
|
|
||||||
}
|
|
||||||
connect(_field, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
|
connect(_field, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
|
||||||
connect(_field, SIGNAL(cancelled()), this, SLOT(onCancel()));
|
connect(_field, SIGNAL(cancelled()), this, SLOT(onCancel()));
|
||||||
connect(_field, SIGNAL(tabbed()), this, SLOT(onFieldTabbed()));
|
connect(_field, SIGNAL(tabbed()), this, SLOT(onFieldTabbed()));
|
||||||
|
@ -3136,6 +3101,11 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
||||||
connect(audioCapture(), SIGNAL(done(QByteArray,VoiceWaveform,qint32)), this, SLOT(onRecordDone(QByteArray,VoiceWaveform,qint32)));
|
connect(audioCapture(), SIGNAL(done(QByteArray,VoiceWaveform,qint32)), this, SLOT(onRecordDone(QByteArray,VoiceWaveform,qint32)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_attachToggle->setClickedCallback([this] { chooseAttach(); });
|
||||||
|
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
|
||||||
|
notifyFileQueryUpdated(update);
|
||||||
|
});
|
||||||
|
|
||||||
_updateHistoryItems.setSingleShot(true);
|
_updateHistoryItems.setSingleShot(true);
|
||||||
connect(&_updateHistoryItems, SIGNAL(timeout()), this, SLOT(onUpdateHistoryItems()));
|
connect(&_updateHistoryItems, SIGNAL(timeout()), this, SLOT(onUpdateHistoryItems()));
|
||||||
|
|
||||||
|
@ -3195,25 +3165,20 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
||||||
_silent->hide();
|
_silent->hide();
|
||||||
_botCommandStart->hide();
|
_botCommandStart->hide();
|
||||||
|
|
||||||
_attachType->setOrigin(Ui::PanelAnimation::Origin::BottomLeft);
|
|
||||||
_attachToggle->installEventFilter(_attachType);
|
|
||||||
_attachEmoji->installEventFilter(_emojiPan);
|
_attachEmoji->installEventFilter(_emojiPan);
|
||||||
|
|
||||||
connect(_botKeyboardShow, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
connect(_botKeyboardShow, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
||||||
connect(_botKeyboardHide, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
connect(_botKeyboardHide, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
||||||
connect(_botCommandStart, SIGNAL(clicked()), this, SLOT(onCmdStart()));
|
connect(_botCommandStart, SIGNAL(clicked()), this, SLOT(onCmdStart()));
|
||||||
|
|
||||||
_attachType->addAction(lang(lng_attach_file), this, SLOT(onDocumentSelect()), &st::historyMediaTypeFile, &st::historyMediaTypeFileOver);
|
|
||||||
_attachType->addAction(lang(lng_attach_photo), this, SLOT(onPhotoSelect()), &st::historyMediaTypePhoto, &st::historyMediaTypePhotoOver);
|
|
||||||
_attachType->hide();
|
|
||||||
_emojiPan->hide();
|
_emojiPan->hide();
|
||||||
_attachDragDocument->hide();
|
_attachDragDocument->hide();
|
||||||
_attachDragPhoto->hide();
|
_attachDragPhoto->hide();
|
||||||
|
|
||||||
_topShadow->hide();
|
_topShadow->hide();
|
||||||
|
|
||||||
connect(_attachDragDocument, SIGNAL(dropped(const QMimeData*)), this, SLOT(onDocumentDrop(const QMimeData*)));
|
_attachDragDocument->setDroppedCallback([this](const QMimeData *data) { confirmSendingFiles(data, CompressConfirm::No); });
|
||||||
connect(_attachDragPhoto, SIGNAL(dropped(const QMimeData*)), this, SLOT(onPhotoDrop(const QMimeData*)));
|
_attachDragPhoto->setDroppedCallback([this](const QMimeData *data) { confirmSendingFiles(data, CompressConfirm::Yes); });
|
||||||
|
|
||||||
connect(&_updateEditTimeLeftDisplay, SIGNAL(timeout()), this, SLOT(updateField()));
|
connect(&_updateEditTimeLeftDisplay, SIGNAL(timeout()), this, SLOT(updateField()));
|
||||||
|
|
||||||
|
@ -3567,11 +3532,13 @@ void HistoryWidget::onRecordError() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::onRecordDone(QByteArray result, VoiceWaveform waveform, qint32 samples) {
|
void HistoryWidget::onRecordDone(QByteArray result, VoiceWaveform waveform, qint32 samples) {
|
||||||
if (!_peer || result.isEmpty()) return;
|
if (!canWriteMessage() || result.isEmpty()) return;
|
||||||
|
|
||||||
App::wnd()->activateWindow();
|
App::wnd()->activateWindow();
|
||||||
int32 duration = samples / AudioVoiceMsgFrequency;
|
auto duration = samples / AudioVoiceMsgFrequency;
|
||||||
_fileLoader.addTask(new FileLoadTask(result, duration, waveform, FileLoadTo(_peer->id, _silent->checked(), replyToId())));
|
auto to = FileLoadTo(_peer->id, _silent->checked(), replyToId());
|
||||||
|
auto caption = QString();
|
||||||
|
_fileLoader.addTask(MakeShared<FileLoadTask>(result, duration, waveform, to, caption));
|
||||||
cancelReplyAfterMediaSend(lastForceReplyReplied());
|
cancelReplyAfterMediaSend(lastForceReplyReplied());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4460,7 +4427,6 @@ void HistoryWidget::updateNotifySettings() {
|
||||||
bool HistoryWidget::contentOverlapped(const QRect &globalRect) {
|
bool HistoryWidget::contentOverlapped(const QRect &globalRect) {
|
||||||
return (_attachDragDocument->overlaps(globalRect) ||
|
return (_attachDragDocument->overlaps(globalRect) ||
|
||||||
_attachDragPhoto->overlaps(globalRect) ||
|
_attachDragPhoto->overlaps(globalRect) ||
|
||||||
_attachType->overlaps(globalRect) ||
|
|
||||||
_fieldAutocomplete->overlaps(globalRect) ||
|
_fieldAutocomplete->overlaps(globalRect) ||
|
||||||
_emojiPan->overlaps(globalRect));
|
_emojiPan->overlaps(globalRect));
|
||||||
}
|
}
|
||||||
|
@ -4563,9 +4529,8 @@ bool HistoryWidget::reportSpamSettingFail(const RPCError &error, mtpRequestId re
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryWidget::canWriteMessage() const {
|
bool HistoryWidget::canWriteMessage() const {
|
||||||
if (!_history || _a_show.animating()) return false;
|
if (!_history || !_canSendMessages) return false;
|
||||||
if (isBlocked() || isJoinChannel() || isMuteUnmute() || isBotStart()) return false;
|
if (isBlocked() || isJoinChannel() || isMuteUnmute() || isBotStart()) return false;
|
||||||
if (!_canSendMessages) return false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4594,7 +4559,6 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_botKeyboardShow->hide();
|
_botKeyboardShow->hide();
|
||||||
_botKeyboardHide->hide();
|
_botKeyboardHide->hide();
|
||||||
_botCommandStart->hide();
|
_botCommandStart->hide();
|
||||||
_attachType->hide();
|
|
||||||
_emojiPan->hide();
|
_emojiPan->hide();
|
||||||
if (_pinnedBar) {
|
if (_pinnedBar) {
|
||||||
_pinnedBar->cancel->hide();
|
_pinnedBar->cancel->hide();
|
||||||
|
@ -4654,7 +4618,6 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_botKeyboardShow->hide();
|
_botKeyboardShow->hide();
|
||||||
_botKeyboardHide->hide();
|
_botKeyboardHide->hide();
|
||||||
_botCommandStart->hide();
|
_botCommandStart->hide();
|
||||||
_attachType->hide();
|
|
||||||
_emojiPan->hide();
|
_emojiPan->hide();
|
||||||
if (!_field->isHidden()) {
|
if (!_field->isHidden()) {
|
||||||
_field->hide();
|
_field->hide();
|
||||||
|
@ -4779,7 +4742,6 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_botKeyboardShow->hide();
|
_botKeyboardShow->hide();
|
||||||
_botKeyboardHide->hide();
|
_botKeyboardHide->hide();
|
||||||
_botCommandStart->hide();
|
_botCommandStart->hide();
|
||||||
_attachType->hide();
|
|
||||||
_emojiPan->hide();
|
_emojiPan->hide();
|
||||||
_kbScroll->hide();
|
_kbScroll->hide();
|
||||||
if (!_field->isHidden()) {
|
if (!_field->isHidden()) {
|
||||||
|
@ -5297,7 +5259,6 @@ bool HistoryWidget::saveEditMsgFail(History *history, const RPCError &error, mtp
|
||||||
|
|
||||||
void HistoryWidget::hideSelectorControlsAnimated() {
|
void HistoryWidget::hideSelectorControlsAnimated() {
|
||||||
_fieldAutocomplete->hideAnimated();
|
_fieldAutocomplete->hideAnimated();
|
||||||
_attachType->hideAnimated();
|
|
||||||
_emojiPan->hideAnimated();
|
_emojiPan->hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5481,17 +5442,6 @@ void HistoryWidget::shareContact(const PeerId &peer, const QString &phone, const
|
||||||
cancelReplyAfterMediaSend(lastKeyboardUsed);
|
cancelReplyAfterMediaSend(lastKeyboardUsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::onSendPaths(const PeerId &peer) {
|
|
||||||
Ui::showPeerHistory(peer, ShowAtTheEndMsgId);
|
|
||||||
if (!_history) return;
|
|
||||||
|
|
||||||
if (cSendPaths().size() == 1) {
|
|
||||||
uploadFile(cSendPaths().at(0), PrepareAuto);
|
|
||||||
} else {
|
|
||||||
uploadFiles(cSendPaths(), PrepareDocument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
History *HistoryWidget::history() const {
|
History *HistoryWidget::history() const {
|
||||||
return _history;
|
return _history;
|
||||||
}
|
}
|
||||||
|
@ -5645,62 +5595,49 @@ void HistoryWidget::step_recording(float64 ms, bool timer) {
|
||||||
if (timer) update(_attachToggle->geometry());
|
if (timer) update(_attachToggle->geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::onPhotoSelect() {
|
void HistoryWidget::chooseAttach() {
|
||||||
if (!_history) return;
|
if (!_history) return;
|
||||||
|
|
||||||
_attachToggle->setIcon(&st::historyAttachPhotoIcon, &st::historyAttachPhotoIconOver);
|
auto photoExtensions = cPhotoExtensions();
|
||||||
_attachType->hideFast();
|
auto imageExtensions = cImgExtensions();
|
||||||
|
auto filter = filedialogAllFilesFilter() + qsl(";;Image files (*") + imageExtensions.join(qsl(" *")) + qsl(");;Photo files (*") + photoExtensions.join(qsl(" *")) + qsl(")");
|
||||||
|
|
||||||
if (cDefaultAttach() != dbidaPhoto) {
|
_attachFilesQueryId = FileDialog::queryReadFiles(lang(lng_choose_files), filter);
|
||||||
cSetDefaultAttach(dbidaPhoto);
|
|
||||||
Local::writeUserSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList photoExtensions(cPhotoExtensions());
|
|
||||||
QStringList imgExtensions(cImgExtensions());
|
|
||||||
QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;Photo files (*") + photoExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter());
|
|
||||||
|
|
||||||
QStringList files;
|
|
||||||
QByteArray content;
|
|
||||||
if (filedialogGetOpenFiles(files, content, lang(lng_choose_images), filter)) {
|
|
||||||
if (!content.isEmpty()) {
|
|
||||||
uploadFileContent(content, PreparePhoto);
|
|
||||||
} else {
|
|
||||||
uploadFiles(files, PreparePhoto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::onDocumentSelect() {
|
void HistoryWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update) {
|
||||||
if (!_history) return;
|
if (_attachFilesQueryId != update.queryId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_attachFilesQueryId = 0;
|
||||||
|
|
||||||
_attachToggle->setIcon(&st::historyAttachFileIcon, &st::historyAttachFileIconOver);
|
if (update.filePaths.isEmpty() && update.remoteContent.isEmpty()) {
|
||||||
_attachType->hideFast();
|
return;
|
||||||
|
|
||||||
if (cDefaultAttach() != dbidaDocument) {
|
|
||||||
cSetDefaultAttach(dbidaDocument);
|
|
||||||
Local::writeUserSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList photoExtensions(cPhotoExtensions());
|
if (!update.remoteContent.isEmpty()) {
|
||||||
QStringList imgExtensions(cImgExtensions());
|
auto animated = false;
|
||||||
QString filter(filedialogAllFilesFilter() + qsl(";;Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;Photo files (*") + photoExtensions.join(qsl(" *")) + qsl(")"));
|
auto image = App::readImage(update.remoteContent, nullptr, false, &animated);
|
||||||
|
if (!image.isNull() && !animated) {
|
||||||
QStringList files;
|
confirmSendingFiles(image, update.remoteContent);
|
||||||
QByteArray content;
|
|
||||||
if (filedialogGetOpenFiles(files, content, lang(lng_choose_images), filter)) {
|
|
||||||
if (!content.isEmpty()) {
|
|
||||||
uploadFileContent(content, PrepareDocument);
|
|
||||||
} else {
|
} else {
|
||||||
uploadFiles(files, PrepareDocument);
|
uploadFile(update.remoteContent, SendMediaType::File);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto lists = getSendingFilesLists(update.filePaths);
|
||||||
|
if (lists.allFilesArePhotos) {
|
||||||
|
confirmSendingFiles(lists);
|
||||||
|
} else {
|
||||||
|
validateSendingFiles(lists, [this](const QStringList &files) {
|
||||||
|
uploadFiles(files, SendMediaType::File);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::dragEnterEvent(QDragEnterEvent *e) {
|
void HistoryWidget::dragEnterEvent(QDragEnterEvent *e) {
|
||||||
if (!_history) return;
|
if (!_history || !_canSendMessages) return;
|
||||||
|
|
||||||
if (_peer && !_canSendMessages) return;
|
|
||||||
|
|
||||||
_attachDrag = getDragState(e->mimeData());
|
_attachDrag = getDragState(e->mimeData());
|
||||||
updateDragAreas();
|
updateDragAreas();
|
||||||
|
@ -5926,7 +5863,7 @@ bool HistoryWidget::botCallbackFail(BotCallbackInfo info, const RPCError &error,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HistoryWidget::insertBotCommand(const QString &cmd, bool specialGif) {
|
bool HistoryWidget::insertBotCommand(const QString &cmd, bool specialGif) {
|
||||||
if (!_history || !canWriteMessage()) return false;
|
if (!canWriteMessage()) return false;
|
||||||
|
|
||||||
bool insertingInlineBot = !cmd.isEmpty() && (cmd.at(0) == '@');
|
bool insertingInlineBot = !cmd.isEmpty() && (cmd.at(0) == '@');
|
||||||
QString toInsert = cmd;
|
QString toInsert = cmd;
|
||||||
|
@ -6002,17 +5939,17 @@ DragState HistoryWidget::getDragState(const QMimeData *d) {
|
||||||
for (QList<QUrl>::const_iterator i = urls.cbegin(), en = urls.cend(); i != en; ++i) {
|
for (QList<QUrl>::const_iterator i = urls.cbegin(), en = urls.cend(); i != en; ++i) {
|
||||||
if (!i->isLocalFile()) return DragStateNone;
|
if (!i->isLocalFile()) return DragStateNone;
|
||||||
|
|
||||||
auto file = psConvertFileUrl(*i);
|
auto file = Platform::FileDialog::UrlToLocal(*i);
|
||||||
|
|
||||||
QFileInfo info(file);
|
QFileInfo info(file);
|
||||||
if (info.isDir()) return DragStateNone;
|
if (info.isDir()) return DragStateNone;
|
||||||
|
|
||||||
quint64 s = info.size();
|
quint64 s = info.size();
|
||||||
if (s >= MaxUploadDocumentSize) {
|
if (s > App::kFileSizeLimit) {
|
||||||
return DragStateNone;
|
return DragStateNone;
|
||||||
}
|
}
|
||||||
if (allAreSmallImages) {
|
if (allAreSmallImages) {
|
||||||
if (s >= MaxUploadPhotoSize) {
|
if (s > App::kImageSizeLimit) {
|
||||||
allAreSmallImages = false;
|
allAreSmallImages = false;
|
||||||
} else {
|
} else {
|
||||||
bool foundImageExtension = false;
|
bool foundImageExtension = false;
|
||||||
|
@ -6156,57 +6093,8 @@ void HistoryWidget::dropEvent(QDropEvent *e) {
|
||||||
e->acceptProposedAction();
|
e->acceptProposedAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::onPhotoDrop(const QMimeData *data) {
|
|
||||||
if (!_history) return;
|
|
||||||
|
|
||||||
QStringList files = getMediasFromMime(data);
|
|
||||||
if (files.isEmpty()) {
|
|
||||||
if (data->hasImage()) {
|
|
||||||
QImage image = qvariant_cast<QImage>(data->imageData());
|
|
||||||
if (image.isNull()) return;
|
|
||||||
|
|
||||||
uploadImage(image, PreparePhoto, FileLoadNoForceConfirm, data->text());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadFiles(files, PreparePhoto);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::onDocumentDrop(const QMimeData *data) {
|
|
||||||
if (!_history) return;
|
|
||||||
|
|
||||||
if (_peer && !_canSendMessages) return;
|
|
||||||
|
|
||||||
QStringList files = getMediasFromMime(data);
|
|
||||||
if (files.isEmpty()) return;
|
|
||||||
|
|
||||||
uploadFiles(files, PrepareDocument);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::onFilesDrop(const QMimeData *data) {
|
|
||||||
|
|
||||||
if (_peer && !_canSendMessages) return;
|
|
||||||
|
|
||||||
QStringList files = getMediasFromMime(data);
|
|
||||||
if (files.isEmpty()) {
|
|
||||||
if (data->hasImage()) {
|
|
||||||
QImage image = qvariant_cast<QImage>(data->imageData());
|
|
||||||
if (image.isNull()) return;
|
|
||||||
|
|
||||||
uploadImage(image, PrepareAuto, FileLoadNoForceConfirm, data->text());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (files.size() == 1 && !QFileInfo(files.at(0)).isDir()) {
|
|
||||||
uploadFile(files.at(0), PrepareAuto);
|
|
||||||
}
|
|
||||||
// uploadFiles(files, PrepareAuto); // multiple confirm with "compressed" checkbox
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::onKbToggle(bool manual) {
|
void HistoryWidget::onKbToggle(bool manual) {
|
||||||
auto fieldEnabled = canWriteMessage();
|
auto fieldEnabled = canWriteMessage() && !_a_show.animating();
|
||||||
if (_kbShown || _kbReplyTo) {
|
if (_kbShown || _kbReplyTo) {
|
||||||
_botKeyboardHide->hide();
|
_botKeyboardHide->hide();
|
||||||
if (_kbShown) {
|
if (_kbShown) {
|
||||||
|
@ -6276,7 +6164,7 @@ void HistoryWidget::onKbToggle(bool manual) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resizeEvent(0);
|
resizeEvent(0);
|
||||||
if (_botKeyboardHide->isHidden() && canWriteMessage()) {
|
if (_botKeyboardHide->isHidden() && canWriteMessage() && !_a_show.animating()) {
|
||||||
_attachEmoji->show();
|
_attachEmoji->show();
|
||||||
} else {
|
} else {
|
||||||
_attachEmoji->hide();
|
_attachEmoji->hide();
|
||||||
|
@ -6525,7 +6413,6 @@ void HistoryWidget::moveFieldControls() {
|
||||||
_silent->moveToRight(right, buttonsBottom);
|
_silent->moveToRight(right, buttonsBottom);
|
||||||
|
|
||||||
_fieldBarCancel->moveToRight(0, _field->y() - st::historySendPadding - _fieldBarCancel->height());
|
_fieldBarCancel->moveToRight(0, _field->y() - st::historySendPadding - _fieldBarCancel->height());
|
||||||
_attachType->moveToLeft(0, _attachToggle->y() - _attachType->height());
|
|
||||||
_emojiPan->moveBottom(_attachEmoji->y());
|
_emojiPan->moveBottom(_attachEmoji->y());
|
||||||
|
|
||||||
auto fullWidthButtonRect = QRect(0, bottom - _botStart->height(), width(), _botStart->height());
|
auto fullWidthButtonRect = QRect(0, bottom - _botStart->height(), width(), _botStart->height());
|
||||||
|
@ -6616,69 +6503,240 @@ void HistoryWidget::updateFieldPlaceholder() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::uploadImage(const QImage &img, PrepareMediaType type, FileLoadForceConfirmType confirm, const QString &source, bool withText) {
|
template <typename SendCallback>
|
||||||
if (!_history) return;
|
bool HistoryWidget::showSendFilesBox(SendFilesBox *box, const QString &insertTextOnCancel, const QString *addedComment, SendCallback callback) {
|
||||||
|
|
||||||
App::wnd()->activateWindow();
|
App::wnd()->activateWindow();
|
||||||
auto task = new FileLoadTask(img, type, FileLoadTo(_peer->id, _silent->checked(), replyToId()), confirm, source);
|
|
||||||
if (withText) {
|
auto withComment = (addedComment != nullptr);
|
||||||
_confirmWithTextId = task->fileid();
|
box->setConfirmedCallback(base::lambda_guarded(this, [this, withComment, sendCallback = std_::move(callback)](const QStringList &files, bool compressed, const QString &caption, bool ctrlShiftEnter) {
|
||||||
|
if (!canWriteMessage()) return;
|
||||||
|
|
||||||
|
auto replyTo = replyToId();
|
||||||
|
if (withComment) {
|
||||||
|
onSend(ctrlShiftEnter, replyTo);
|
||||||
}
|
}
|
||||||
_fileLoader.addTask(task);
|
sendCallback(files, compressed, caption, replyTo);
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (withComment) {
|
||||||
|
auto was = _field->getTextWithTags();
|
||||||
|
setFieldText({ *addedComment, TextWithTags::Tags() });
|
||||||
|
box->setCancelledCallback(base::lambda_guarded(this, [this, was] {
|
||||||
|
setFieldText(was);
|
||||||
|
}));
|
||||||
|
} else if (!insertTextOnCancel.isEmpty()) {
|
||||||
|
box->setCancelledCallback(base::lambda_guarded(this, [this, insertTextOnCancel] {
|
||||||
|
_field->textCursor().insertText(insertTextOnCancel);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ui::showLayer(box);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::uploadFile(const QString &file, PrepareMediaType type, FileLoadForceConfirmType confirm, bool withText) {
|
template <typename Callback>
|
||||||
if (!_history) return;
|
bool HistoryWidget::validateSendingFiles(const SendingFilesLists &lists, Callback callback) {
|
||||||
|
if (!canWriteMessage()) return false;
|
||||||
|
|
||||||
App::wnd()->activateWindow();
|
App::wnd()->activateWindow();
|
||||||
FileLoadTask *task = new FileLoadTask(file, type, FileLoadTo(_peer->id, _silent->checked(), replyToId()), confirm);
|
if (!lists.nonLocalUrls.isEmpty()) {
|
||||||
if (withText) {
|
Ui::showLayer(new InformBox(lng_send_image_non_local(lt_name, lists.nonLocalUrls.front().toDisplayString())));
|
||||||
_confirmWithTextId = task->fileid();
|
} else if (!lists.emptyFiles.isEmpty()) {
|
||||||
|
Ui::showLayer(new InformBox(lng_send_image_empty(lt_name, lists.emptyFiles.front())));
|
||||||
|
} else if (!lists.tooLargeFiles.isEmpty()) {
|
||||||
|
Ui::showLayer(new InformBox(lng_send_image_too_large(lt_name, lists.tooLargeFiles.front())));
|
||||||
|
} else if (!lists.filesToSend.isEmpty()) {
|
||||||
|
return callback(lists.filesToSend);
|
||||||
}
|
}
|
||||||
_fileLoader.addTask(task);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::uploadFiles(const QStringList &files, PrepareMediaType type) {
|
bool HistoryWidget::confirmSendingFiles(const QList<QUrl> &files, CompressConfirm compressed, const QString *addedComment) {
|
||||||
if (!_history || files.isEmpty()) return;
|
return confirmSendingFiles(getSendingFilesLists(files), compressed, addedComment);
|
||||||
|
}
|
||||||
|
|
||||||
if (files.size() == 1 && !QFileInfo(files.at(0)).isDir()) return uploadFile(files.at(0), type);
|
bool HistoryWidget::confirmSendingFiles(const QStringList &files, CompressConfirm compressed, const QString *addedComment) {
|
||||||
|
return confirmSendingFiles(getSendingFilesLists(files), compressed, addedComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryWidget::confirmSendingFiles(const SendingFilesLists &lists, CompressConfirm compressed, const QString *addedComment) {
|
||||||
|
return validateSendingFiles(lists, [this, &lists, compressed, addedComment](const QStringList &files) {
|
||||||
|
auto image = QImage();
|
||||||
|
auto insertTextOnCancel = QString();
|
||||||
|
auto prepareBox = [this, &files, &lists, compressed, &image] {
|
||||||
|
if (files.size() > 1) {
|
||||||
|
return new SendFilesBox(files, lists.allFilesArePhotos ? compressed : CompressConfirm::None);
|
||||||
|
}
|
||||||
|
auto filepath = files.front();
|
||||||
|
auto animated = false;
|
||||||
|
image = App::readImage(filepath, nullptr, false, &animated);
|
||||||
|
return new SendFilesBox(filepath, image, imageCompressConfirm(image, compressed, animated), animated);
|
||||||
|
};
|
||||||
|
auto sendCallback = [this, image](const QStringList &files, bool compressed, const QString &caption, MsgId replyTo) {
|
||||||
|
auto type = compressed ? SendMediaType::Photo : SendMediaType::File;
|
||||||
|
uploadFilesAfterConfirmation(files, image, QByteArray(), type, caption);
|
||||||
|
};
|
||||||
|
return showSendFilesBox(prepareBox(), insertTextOnCancel, addedComment, std_::move(sendCallback));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryWidget::confirmSendingFiles(const QImage &image, const QByteArray &content, CompressConfirm compressed, const QString &insertTextOnCancel) {
|
||||||
|
if (!canWriteMessage() || image.isNull()) return false;
|
||||||
|
|
||||||
App::wnd()->activateWindow();
|
App::wnd()->activateWindow();
|
||||||
|
auto animated = false;
|
||||||
|
auto box = new SendFilesBox(QString(), image, imageCompressConfirm(image, compressed), animated);
|
||||||
|
auto sendCallback = [this, content, image](const QStringList &files, bool compressed, const QString &caption, MsgId replyTo) {
|
||||||
|
auto type = compressed ? SendMediaType::Photo : SendMediaType::File;
|
||||||
|
uploadFilesAfterConfirmation(files, image, content, type, caption);
|
||||||
|
};
|
||||||
|
return showSendFilesBox(box, insertTextOnCancel, nullptr, std_::move(sendCallback));
|
||||||
|
}
|
||||||
|
|
||||||
FileLoadTo to(_peer->id, _silent->checked(), replyToId());
|
bool HistoryWidget::confirmSendingFiles(const QMimeData *data, CompressConfirm compressed, const QString &insertTextOnCancel) {
|
||||||
|
if (!canWriteMessage()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
TasksList tasks;
|
auto &urls = data->urls();
|
||||||
|
if (!urls.isEmpty()) {
|
||||||
|
for_const (auto &url, urls) {
|
||||||
|
if (url.isLocalFile()) {
|
||||||
|
confirmSendingFiles(urls, compressed);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data->hasImage()) {
|
||||||
|
auto image = qvariant_cast<QImage>(data->imageData());
|
||||||
|
if (!image.isNull()) {
|
||||||
|
confirmSendingFiles(image, QByteArray(), compressed, insertTextOnCancel);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryWidget::confirmShareContact(const QString &phone, const QString &fname, const QString &lname, const QString *addedComment) {
|
||||||
|
if (!canWriteMessage()) return false;
|
||||||
|
|
||||||
|
auto box = new SendFilesBox(phone, fname, lname);
|
||||||
|
auto sendCallback = [this, phone, fname, lname](const QStringList &files, bool compressed, const QString &caption, MsgId replyTo) {
|
||||||
|
shareContact(_peer->id, phone, fname, lname, replyTo);
|
||||||
|
};
|
||||||
|
auto insertTextOnCancel = QString();
|
||||||
|
return showSendFilesBox(box, insertTextOnCancel, addedComment, std_::move(sendCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryWidget::SendingFilesLists HistoryWidget::getSendingFilesLists(const QList<QUrl> &files) {
|
||||||
|
auto result = SendingFilesLists();
|
||||||
|
for_const (auto &url, files) {
|
||||||
|
if (!url.isLocalFile()) {
|
||||||
|
result.nonLocalUrls.push_back(url);
|
||||||
|
} else {
|
||||||
|
auto filepath = Platform::FileDialog::UrlToLocal(url);
|
||||||
|
getSendingLocalFileInfo(result, filepath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryWidget::SendingFilesLists HistoryWidget::getSendingFilesLists(const QStringList &files) {
|
||||||
|
auto result = SendingFilesLists();
|
||||||
|
for_const (auto &filepath, files) {
|
||||||
|
getSendingLocalFileInfo(result, filepath);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::getSendingLocalFileInfo(SendingFilesLists &result, const QString &filepath) {
|
||||||
|
auto hasPhotoExtension = [](const QString &filepath) {
|
||||||
|
for_const (auto extension, cPhotoExtensions()) {
|
||||||
|
if (filepath.right(extension.size()).compare(extension, Qt::CaseInsensitive) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
auto fileinfo = QFileInfo(filepath);
|
||||||
|
if (fileinfo.isDir()) {
|
||||||
|
result.directories.push_back(filepath);
|
||||||
|
} else {
|
||||||
|
auto filesize = fileinfo.size();
|
||||||
|
if (filesize <= 0) {
|
||||||
|
result.emptyFiles.push_back(filepath);
|
||||||
|
} else if (filesize > App::kFileSizeLimit) {
|
||||||
|
result.tooLargeFiles.push_back(filepath);
|
||||||
|
} else {
|
||||||
|
result.filesToSend.push_back(filepath);
|
||||||
|
if (result.allFilesArePhotos) {
|
||||||
|
if (filesize > App::kImageSizeLimit || !hasPhotoExtension(filepath)) {
|
||||||
|
result.allFilesArePhotos = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressConfirm HistoryWidget::imageCompressConfirm(const QImage &image, CompressConfirm compressed, bool animated) {
|
||||||
|
if (animated || image.isNull()) {
|
||||||
|
return CompressConfirm::None;
|
||||||
|
}
|
||||||
|
auto imageWidth = image.width();
|
||||||
|
auto imageHeight = image.height();
|
||||||
|
if (imageWidth >= 20 * imageHeight || imageHeight >= 20 * imageWidth) {
|
||||||
|
return CompressConfirm::None;
|
||||||
|
}
|
||||||
|
return compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::uploadFiles(const QStringList &files, SendMediaType type) {
|
||||||
|
if (!canWriteMessage()) return;
|
||||||
|
|
||||||
|
auto caption = QString();
|
||||||
|
uploadFilesAfterConfirmation(files, QImage(), QByteArray(), type, caption);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::uploadFilesAfterConfirmation(const QStringList &files, const QImage &image, const QByteArray &content, SendMediaType type, QString caption) {
|
||||||
|
t_assert(canWriteMessage());
|
||||||
|
|
||||||
|
auto to = FileLoadTo(_peer->id, _silent->checked(), replyToId());
|
||||||
|
if (files.size() > 1 && !caption.isEmpty()) {
|
||||||
|
MainWidget::MessageToSend message;
|
||||||
|
message.history = _history;
|
||||||
|
message.textWithTags = { caption, TextWithTags::Tags() };
|
||||||
|
message.replyTo = to.replyTo;
|
||||||
|
message.silent = to.silent;
|
||||||
|
message.clearDraft = false;
|
||||||
|
App::main()->sendMessage(message);
|
||||||
|
caption = QString();
|
||||||
|
}
|
||||||
|
auto tasks = TasksList();
|
||||||
tasks.reserve(files.size());
|
tasks.reserve(files.size());
|
||||||
for (int32 i = 0, l = files.size(); i < l; ++i) {
|
for_const (auto &filepath, files) {
|
||||||
tasks.push_back(TaskPtr(new FileLoadTask(files.at(i), type, to, FileLoadNeverConfirm)));
|
if (filepath.isEmpty() && (!image.isNull() || !content.isNull())) {
|
||||||
|
tasks.push_back(MakeShared<FileLoadTask>(content, image, type, to, caption));
|
||||||
|
} else {
|
||||||
|
tasks.push_back(MakeShared<FileLoadTask>(filepath, type, to, caption));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_fileLoader.addTasks(tasks);
|
_fileLoader.addTasks(tasks);
|
||||||
|
|
||||||
cancelReplyAfterMediaSend(lastForceReplyReplied());
|
cancelReplyAfterMediaSend(lastForceReplyReplied());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::uploadFileContent(const QByteArray &fileContent, PrepareMediaType type) {
|
void HistoryWidget::uploadFile(const QByteArray &fileContent, SendMediaType type) {
|
||||||
if (!_history) return;
|
if (!canWriteMessage()) return;
|
||||||
|
|
||||||
|
auto to = FileLoadTo(_peer->id, _silent->checked(), replyToId());
|
||||||
|
auto caption = QString();
|
||||||
|
_fileLoader.addTask(MakeShared<FileLoadTask>(fileContent, type, to, caption));
|
||||||
|
|
||||||
App::wnd()->activateWindow();
|
|
||||||
_fileLoader.addTask(new FileLoadTask(fileContent, type, FileLoadTo(_peer->id, _silent->checked(), replyToId())));
|
|
||||||
cancelReplyAfterMediaSend(lastForceReplyReplied());
|
cancelReplyAfterMediaSend(lastForceReplyReplied());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::shareContactWithConfirm(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, bool withText) {
|
void HistoryWidget::sendFileConfirmed(const FileLoadResultPtr &file) {
|
||||||
if (!_history) return;
|
|
||||||
|
|
||||||
App::wnd()->activateWindow();
|
|
||||||
_confirmWithTextId = 0xFFFFFFFFFFFFFFFFL;
|
|
||||||
Ui::showLayer(new PhotoSendBox(phone, fname, lname, replyTo));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::confirmSendFile(const FileLoadResultPtr &file, bool ctrlShiftEnter) {
|
|
||||||
bool lastKeyboardUsed = lastForceReplyReplied(FullMsgId(peerToChannel(file->to.peer), file->to.replyTo));
|
bool lastKeyboardUsed = lastForceReplyReplied(FullMsgId(peerToChannel(file->to.peer), file->to.replyTo));
|
||||||
if (_confirmWithTextId && _confirmWithTextId == file->id) {
|
|
||||||
onSend(ctrlShiftEnter, file->to.replyTo);
|
|
||||||
_confirmWithTextId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
FullMsgId newId(peerToChannel(file->to.peer), clientMsgId());
|
FullMsgId newId(peerToChannel(file->to.peer), clientMsgId());
|
||||||
|
|
||||||
|
@ -6711,11 +6769,11 @@ void HistoryWidget::confirmSendFile(const FileLoadResultPtr &file, bool ctrlShif
|
||||||
if (silentPost) {
|
if (silentPost) {
|
||||||
flags |= MTPDmessage::Flag::f_silent;
|
flags |= MTPDmessage::Flag::f_silent;
|
||||||
}
|
}
|
||||||
if (file->type == PreparePhoto) {
|
if (file->type == SendMediaType::Photo) {
|
||||||
h->addNewMessage(MTP_message(MTP_flags(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(file->photo, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
|
h->addNewMessage(MTP_message(MTP_flags(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(file->photo, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
|
||||||
} else if (file->type == PrepareDocument) {
|
} else if (file->type == SendMediaType::File) {
|
||||||
h->addNewMessage(MTP_message(MTP_flags(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
|
h->addNewMessage(MTP_message(MTP_flags(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
|
||||||
} else if (file->type == PrepareAudio) {
|
} else if (file->type == SendMediaType::Audio) {
|
||||||
if (!h->peer->isChannel()) {
|
if (!h->peer->isChannel()) {
|
||||||
flags |= MTPDmessage::Flag::f_media_unread;
|
flags |= MTPDmessage::Flag::f_media_unread;
|
||||||
}
|
}
|
||||||
|
@ -6731,34 +6789,6 @@ void HistoryWidget::confirmSendFile(const FileLoadResultPtr &file, bool ctrlShif
|
||||||
cancelReplyAfterMediaSend(lastKeyboardUsed);
|
cancelReplyAfterMediaSend(lastKeyboardUsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::cancelSendFile(const FileLoadResultPtr &file) {
|
|
||||||
if (_confirmWithTextId && file->id == _confirmWithTextId) {
|
|
||||||
clearFieldText();
|
|
||||||
_confirmWithTextId = 0;
|
|
||||||
}
|
|
||||||
if (!file->originalText.isEmpty()) {
|
|
||||||
_field->textCursor().insertText(file->originalText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::confirmShareContact(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, bool ctrlShiftEnter) {
|
|
||||||
if (!_peer) return;
|
|
||||||
|
|
||||||
PeerId shareToId = _peer->id;
|
|
||||||
if (_confirmWithTextId == 0xFFFFFFFFFFFFFFFFL) {
|
|
||||||
onSend(ctrlShiftEnter, replyTo);
|
|
||||||
_confirmWithTextId = 0;
|
|
||||||
}
|
|
||||||
shareContact(shareToId, phone, fname, lname, replyTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::cancelShareContact() {
|
|
||||||
if (_confirmWithTextId == 0xFFFFFFFFFFFFFFFFL) {
|
|
||||||
clearFieldText();
|
|
||||||
_confirmWithTextId = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file) {
|
void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, bool silent, const MTPInputFile &file) {
|
||||||
if (!MTP::authedId()) return;
|
if (!MTP::authedId()) return;
|
||||||
HistoryItem *item = App::histItemById(newId);
|
HistoryItem *item = App::histItemById(newId);
|
||||||
|
@ -7688,7 +7718,6 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
|
||||||
if (_membersDropdown) {
|
if (_membersDropdown) {
|
||||||
_membersDropdown->raise();
|
_membersDropdown->raise();
|
||||||
}
|
}
|
||||||
_attachType->raise();
|
|
||||||
_emojiPan->raise();
|
_emojiPan->raise();
|
||||||
_attachDragDocument->raise();
|
_attachDragDocument->raise();
|
||||||
_attachDragPhoto->raise();
|
_attachDragPhoto->raise();
|
||||||
|
@ -8868,42 +8897,6 @@ void HistoryWidget::destroyData() {
|
||||||
showHistory(0, 0);
|
showHistory(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList HistoryWidget::getMediasFromMime(const QMimeData *d) {
|
|
||||||
QString uriListFormat(qsl("text/uri-list"));
|
|
||||||
QStringList photoExtensions(cPhotoExtensions()), files;
|
|
||||||
if (!d->hasFormat(uriListFormat)) return QStringList();
|
|
||||||
|
|
||||||
const QList<QUrl> &urls(d->urls());
|
|
||||||
if (urls.isEmpty()) return QStringList();
|
|
||||||
|
|
||||||
files.reserve(urls.size());
|
|
||||||
for (QList<QUrl>::const_iterator i = urls.cbegin(), en = urls.cend(); i != en; ++i) {
|
|
||||||
if (!i->isLocalFile()) return QStringList();
|
|
||||||
|
|
||||||
auto file = psConvertFileUrl(*i);
|
|
||||||
|
|
||||||
QFileInfo info(file);
|
|
||||||
uint64 s = info.size();
|
|
||||||
if (s >= MaxUploadDocumentSize) {
|
|
||||||
if (s >= MaxUploadPhotoSize) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
bool foundGoodExtension = false;
|
|
||||||
for (QStringList::const_iterator j = photoExtensions.cbegin(), end = photoExtensions.cend(); j != end; ++j) {
|
|
||||||
if (file.right(j->size()).toLower() == (*j).toLower()) {
|
|
||||||
foundGoodExtension = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!foundGoodExtension) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
files.push_back(file);
|
|
||||||
}
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPoint HistoryWidget::clampMousePosition(QPoint point) {
|
QPoint HistoryWidget::clampMousePosition(QPoint point) {
|
||||||
if (point.x() < 0) {
|
if (point.x() < 0) {
|
||||||
point.setX(0);
|
point.setX(0);
|
||||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "localimageloader.h"
|
#include "localimageloader.h"
|
||||||
|
#include "ui/filedialog.h"
|
||||||
#include "ui/effects/rect_shadow.h"
|
#include "ui/effects/rect_shadow.h"
|
||||||
#include "ui/widgets/tooltip.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
|
@ -53,6 +54,7 @@ class RoundButton;
|
||||||
class DragArea;
|
class DragArea;
|
||||||
class EmojiPan;
|
class EmojiPan;
|
||||||
class SilentToggle;
|
class SilentToggle;
|
||||||
|
class SendFilesBox;
|
||||||
|
|
||||||
class HistoryWidget;
|
class HistoryWidget;
|
||||||
class HistoryInner : public TWidget, public Ui::AbstractTooltipShower, private base::Subscriber {
|
class HistoryInner : public TWidget, public Ui::AbstractTooltipShower, private base::Subscriber {
|
||||||
|
@ -582,16 +584,16 @@ public:
|
||||||
void updateFieldPlaceholder();
|
void updateFieldPlaceholder();
|
||||||
void updateStickersByEmoji();
|
void updateStickersByEmoji();
|
||||||
|
|
||||||
void uploadImage(const QImage &img, PrepareMediaType type, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, const QString &source = QString(), bool withText = false);
|
bool confirmSendingFiles(const QList<QUrl> &files, CompressConfirm compressed = CompressConfirm::Auto, const QString *addedComment = nullptr);
|
||||||
void uploadFile(const QString &file, PrepareMediaType type, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, bool withText = false); // with confirmation
|
bool confirmSendingFiles(const QStringList &files, CompressConfirm compressed = CompressConfirm::Auto, const QString *addedComment = nullptr);
|
||||||
void uploadFiles(const QStringList &files, PrepareMediaType type);
|
bool confirmSendingFiles(const QImage &image, const QByteArray &content, CompressConfirm compressed = CompressConfirm::Auto, const QString &insertTextOnCancel = QString());
|
||||||
void uploadFileContent(const QByteArray &fileContent, PrepareMediaType type);
|
bool confirmSendingFiles(const QMimeData *data, CompressConfirm compressed = CompressConfirm::Auto, const QString &insertTextOnCancel = QString());
|
||||||
void shareContactWithConfirm(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, bool withText = false);
|
bool confirmShareContact(const QString &phone, const QString &fname, const QString &lname, const QString *addedComment = nullptr);
|
||||||
|
|
||||||
void confirmSendFile(const FileLoadResultPtr &file, bool ctrlShiftEnter);
|
void uploadFile(const QByteArray &fileContent, SendMediaType type);
|
||||||
void cancelSendFile(const FileLoadResultPtr &file);
|
void uploadFiles(const QStringList &files, SendMediaType type);
|
||||||
void confirmShareContact(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, bool ctrlShiftEnter);
|
|
||||||
void cancelShareContact();
|
void sendFileConfirmed(const FileLoadResultPtr &file);
|
||||||
|
|
||||||
void updateControlsVisibility();
|
void updateControlsVisibility();
|
||||||
void updateControlsGeometry();
|
void updateControlsGeometry();
|
||||||
|
@ -599,7 +601,6 @@ public:
|
||||||
void updateOnlineDisplayTimer();
|
void updateOnlineDisplayTimer();
|
||||||
|
|
||||||
void onShareContact(const PeerId &peer, UserData *contact);
|
void onShareContact(const PeerId &peer, UserData *contact);
|
||||||
void onSendPaths(const PeerId &peer);
|
|
||||||
|
|
||||||
void shareContact(const PeerId &peer, const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, int32 userId = 0);
|
void shareContact(const PeerId &peer, const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, int32 userId = 0);
|
||||||
|
|
||||||
|
@ -788,12 +789,6 @@ public slots:
|
||||||
void onMuteUnmute();
|
void onMuteUnmute();
|
||||||
void onBroadcastSilentChange();
|
void onBroadcastSilentChange();
|
||||||
|
|
||||||
void onPhotoSelect();
|
|
||||||
void onDocumentSelect();
|
|
||||||
void onPhotoDrop(const QMimeData *data);
|
|
||||||
void onDocumentDrop(const QMimeData *data);
|
|
||||||
void onFilesDrop(const QMimeData *data);
|
|
||||||
|
|
||||||
void onKbToggle(bool manual = true);
|
void onKbToggle(bool manual = true);
|
||||||
void onCmdStart();
|
void onCmdStart();
|
||||||
|
|
||||||
|
@ -854,6 +849,29 @@ private slots:
|
||||||
void updateField();
|
void updateField();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void chooseAttach();
|
||||||
|
void notifyFileQueryUpdated(const FileDialog::QueryUpdate &update);
|
||||||
|
struct SendingFilesLists {
|
||||||
|
QList<QUrl> nonLocalUrls;
|
||||||
|
QStringList directories;
|
||||||
|
QStringList emptyFiles;
|
||||||
|
QStringList tooLargeFiles;
|
||||||
|
QStringList filesToSend;
|
||||||
|
bool allFilesArePhotos = true;
|
||||||
|
};
|
||||||
|
SendingFilesLists getSendingFilesLists(const QList<QUrl> &files);
|
||||||
|
SendingFilesLists getSendingFilesLists(const QStringList &files);
|
||||||
|
void getSendingLocalFileInfo(SendingFilesLists &result, const QString &filepath);
|
||||||
|
bool confirmSendingFiles(const SendingFilesLists &lists, CompressConfirm compressed = CompressConfirm::Auto, const QString *addedComment = nullptr);
|
||||||
|
template <typename Callback>
|
||||||
|
bool validateSendingFiles(const SendingFilesLists &lists, Callback callback);
|
||||||
|
template <typename SendCallback>
|
||||||
|
bool showSendFilesBox(SendFilesBox *box, const QString &insertTextOnCancel, const QString *addedComment, SendCallback callback);
|
||||||
|
CompressConfirm imageCompressConfirm(const QImage &image, CompressConfirm compressed, bool animated = false);
|
||||||
|
|
||||||
|
// If an empty filepath is found we upload (possible) "image" with (possible) "content".
|
||||||
|
void uploadFilesAfterConfirmation(const QStringList &files, const QImage &image, const QByteArray &content, SendMediaType type, QString caption);
|
||||||
|
|
||||||
void itemRemoved(HistoryItem *item);
|
void itemRemoved(HistoryItem *item);
|
||||||
|
|
||||||
// Updates position of controls around the message field,
|
// Updates position of controls around the message field,
|
||||||
|
@ -1032,8 +1050,6 @@ private:
|
||||||
setFieldText(TextWithTags(), events, undoHistoryAction);
|
setFieldText(TextWithTags(), events, undoHistoryAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList getMediasFromMime(const QMimeData *d);
|
|
||||||
|
|
||||||
void updateDragAreas();
|
void updateDragAreas();
|
||||||
|
|
||||||
// when scroll position or scroll area size changed this method
|
// when scroll position or scroll area size changed this method
|
||||||
|
@ -1119,6 +1135,8 @@ private:
|
||||||
anim::fvalue a_recordCancelActive;
|
anim::fvalue a_recordCancelActive;
|
||||||
int32 _recordCancelWidth;
|
int32 _recordCancelWidth;
|
||||||
|
|
||||||
|
FileDialog::QueryId _attachFilesQueryId = 0;
|
||||||
|
|
||||||
bool kbWasHidden() const;
|
bool kbWasHidden() const;
|
||||||
|
|
||||||
bool _kbShown = false;
|
bool _kbShown = false;
|
||||||
|
@ -1129,7 +1147,6 @@ private:
|
||||||
ChildWidget<Ui::InnerDropdown> _membersDropdown = { nullptr };
|
ChildWidget<Ui::InnerDropdown> _membersDropdown = { nullptr };
|
||||||
QTimer _membersDropdownShowTimer;
|
QTimer _membersDropdownShowTimer;
|
||||||
|
|
||||||
ChildWidget<Ui::DropdownMenu> _attachType;
|
|
||||||
ChildWidget<EmojiPan> _emojiPan;
|
ChildWidget<EmojiPan> _emojiPan;
|
||||||
DragState _attachDrag = DragStateNone;
|
DragState _attachDrag = DragStateNone;
|
||||||
ChildWidget<DragArea> _attachDragDocument, _attachDragPhoto;
|
ChildWidget<DragArea> _attachDragDocument, _attachDragPhoto;
|
||||||
|
@ -1142,8 +1159,6 @@ private:
|
||||||
int64 _serviceImageCacheSize = 0;
|
int64 _serviceImageCacheSize = 0;
|
||||||
QString _confirmSource;
|
QString _confirmSource;
|
||||||
|
|
||||||
uint64 _confirmWithTextId = 0;
|
|
||||||
|
|
||||||
QString _titlePeerText;
|
QString _titlePeerText;
|
||||||
bool _titlePeerTextOnline = false;
|
bool _titlePeerTextOnline = false;
|
||||||
int _titlePeerTextWidth = 0;
|
int _titlePeerTextWidth = 0;
|
||||||
|
|
|
@ -282,7 +282,7 @@ void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
|
||||||
if (!document->thumb->isNull()) {
|
if (!document->thumb->isNull()) {
|
||||||
if (document->thumb->loaded()) {
|
if (document->thumb->loaded()) {
|
||||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||||
_thumb = document->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
|
_thumb = document->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
document->thumb->load();
|
document->thumb->load();
|
||||||
|
@ -293,7 +293,7 @@ void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
|
||||||
if (!thumb->isNull()) {
|
if (!thumb->isNull()) {
|
||||||
if (thumb->loaded()) {
|
if (thumb->loaded()) {
|
||||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||||
_thumb = thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
|
_thumb = thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thumb->load();
|
thumb->load();
|
||||||
|
@ -529,13 +529,13 @@ void Photo::prepareThumb(int32 width, int32 height, const QSize &frame) const {
|
||||||
if (PhotoData *photo = getShownPhoto()) {
|
if (PhotoData *photo = getShownPhoto()) {
|
||||||
if (photo->medium->loaded()) {
|
if (photo->medium->loaded()) {
|
||||||
if (!_thumbLoaded || _thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
if (!_thumbLoaded || _thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||||
_thumb = photo->medium->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
|
_thumb = photo->medium->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||||
}
|
}
|
||||||
_thumbLoaded = true;
|
_thumbLoaded = true;
|
||||||
} else {
|
} else {
|
||||||
if (photo->thumb->loaded()) {
|
if (photo->thumb->loaded()) {
|
||||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||||
_thumb = photo->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
|
_thumb = photo->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
photo->medium->load();
|
photo->medium->load();
|
||||||
|
@ -544,7 +544,7 @@ void Photo::prepareThumb(int32 width, int32 height, const QSize &frame) const {
|
||||||
ImagePtr thumb = getResultThumb();
|
ImagePtr thumb = getResultThumb();
|
||||||
if (thumb->loaded()) {
|
if (thumb->loaded()) {
|
||||||
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
|
||||||
_thumb = thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
|
_thumb = thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thumb->load();
|
thumb->load();
|
||||||
|
@ -654,7 +654,7 @@ void Video::prepareThumb(int32 width, int32 height) const {
|
||||||
w = width;
|
w = width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
|
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thumb->load();
|
thumb->load();
|
||||||
|
@ -985,7 +985,7 @@ void Contact::prepareThumb(int width, int height) const {
|
||||||
w = width;
|
w = width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
|
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thumb->load();
|
thumb->load();
|
||||||
|
@ -1132,7 +1132,7 @@ void Article::prepareThumb(int width, int height) const {
|
||||||
w = width;
|
w = width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
|
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thumb->load();
|
thumb->load();
|
||||||
|
@ -1312,7 +1312,7 @@ void Game::prepareThumb(int width, int height) const {
|
||||||
w = width;
|
w = width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
|
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thumb->load();
|
thumb->load();
|
||||||
|
|
|
@ -45,7 +45,7 @@ SignupWidget::SignupWidget(QWidget *parent, Widget::Data *data) : Step(parent, d
|
||||||
_photo->setClickedCallback([this] {
|
_photo->setClickedCallback([this] {
|
||||||
auto imgExtensions = cImgExtensions();
|
auto imgExtensions = cImgExtensions();
|
||||||
auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter();
|
auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter();
|
||||||
_readPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_images), filter);
|
_readPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_image), filter);
|
||||||
});
|
});
|
||||||
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
|
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
|
||||||
notifyFileQueryUpdated(update);
|
notifyFileQueryUpdated(update);
|
||||||
|
|
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
|
||||||
#include "boxes/photosendbox.h"
|
#include "boxes/send_files_box.h"
|
||||||
#include "media/media_clip_reader.h"
|
#include "media/media_clip_reader.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
@ -172,39 +172,34 @@ void TaskQueueWorker::onTaskAdded() {
|
||||||
_inTaskAdded = false;
|
_inTaskAdded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLoadTask::FileLoadTask(const QString &filepath, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm) : _id(rand_value<uint64>())
|
FileLoadTask::FileLoadTask(const QString &filepath, SendMediaType type, const FileLoadTo &to, const QString &caption) : _id(rand_value<uint64>())
|
||||||
, _to(to)
|
, _to(to)
|
||||||
, _filepath(filepath)
|
, _filepath(filepath)
|
||||||
, _type(type)
|
, _type(type)
|
||||||
, _confirm(confirm) {
|
, _caption(caption) {
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLoadTask::FileLoadTask(const QByteArray &content, PrepareMediaType type, const FileLoadTo &to) : _id(rand_value<uint64>())
|
FileLoadTask::FileLoadTask(const QByteArray &content, const QImage &image, SendMediaType type, const FileLoadTo &to, const QString &caption) : _id(rand_value<uint64>())
|
||||||
, _to(to)
|
, _to(to)
|
||||||
, _content(content)
|
, _content(content)
|
||||||
, _type(type) {
|
|
||||||
}
|
|
||||||
|
|
||||||
FileLoadTask::FileLoadTask(const QImage &image, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm, const QString &originalText) : _id(rand_value<uint64>())
|
|
||||||
, _to(to)
|
|
||||||
, _image(image)
|
, _image(image)
|
||||||
, _type(type)
|
, _type(type)
|
||||||
, _confirm(confirm)
|
, _caption(caption) {
|
||||||
, _originalText(originalText) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLoadTask::FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to) : _id(rand_value<uint64>())
|
FileLoadTask::FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to, const QString &caption) : _id(rand_value<uint64>())
|
||||||
, _to(to)
|
, _to(to)
|
||||||
, _content(voice)
|
, _content(voice)
|
||||||
, _duration(duration)
|
, _duration(duration)
|
||||||
, _waveform(waveform)
|
, _waveform(waveform)
|
||||||
, _type(PrepareAudio) {
|
, _type(SendMediaType::Audio)
|
||||||
|
, _caption(caption) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileLoadTask::process() {
|
void FileLoadTask::process() {
|
||||||
const QString stickerMime = qsl("image/webp");
|
const QString stickerMime = qsl("image/webp");
|
||||||
|
|
||||||
_result = FileLoadResultPtr(new FileLoadResult(_id, _to, _originalText));
|
_result = MakeShared<FileLoadResult>(_id, _to, _caption);
|
||||||
|
|
||||||
QString filename, filemime;
|
QString filename, filemime;
|
||||||
qint64 filesize = 0;
|
qint64 filesize = 0;
|
||||||
|
@ -214,8 +209,11 @@ void FileLoadTask::process() {
|
||||||
QString thumbname = "thumb.jpg";
|
QString thumbname = "thumb.jpg";
|
||||||
QByteArray thumbdata;
|
QByteArray thumbdata;
|
||||||
|
|
||||||
bool animated = false, song = false, gif = false, voice = (_type == PrepareAudio);
|
auto animated = false;
|
||||||
QImage fullimage = _image;
|
auto song = false;
|
||||||
|
auto gif = false;
|
||||||
|
auto voice = (_type == SendMediaType::Audio);
|
||||||
|
auto fullimage = base::take(_image);
|
||||||
|
|
||||||
if (!_filepath.isEmpty()) {
|
if (!_filepath.isEmpty()) {
|
||||||
QFileInfo info(_filepath);
|
QFileInfo info(_filepath);
|
||||||
|
@ -226,24 +224,23 @@ void FileLoadTask::process() {
|
||||||
filesize = info.size();
|
filesize = info.size();
|
||||||
filemime = mimeTypeForFile(info).name();
|
filemime = mimeTypeForFile(info).name();
|
||||||
filename = info.fileName();
|
filename = info.fileName();
|
||||||
if (filesize <= MaxUploadPhotoSize && !voice) {
|
auto opaque = (filemime != stickerMime);
|
||||||
bool opaque = (filemime != stickerMime);
|
|
||||||
fullimage = App::readImage(_filepath, 0, opaque, &animated);
|
fullimage = App::readImage(_filepath, 0, opaque, &animated);
|
||||||
}
|
|
||||||
} else if (!_content.isEmpty()) {
|
} else if (!_content.isEmpty()) {
|
||||||
filesize = _content.size();
|
filesize = _content.size();
|
||||||
if (voice) {
|
if (voice) {
|
||||||
filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
|
filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
|
||||||
filemime = "audio/ogg";
|
filemime = "audio/ogg";
|
||||||
} else {
|
} else {
|
||||||
MimeType mimeType = mimeTypeForData(_content);
|
auto mimeType = mimeTypeForData(_content);
|
||||||
filemime = mimeType.name();
|
filemime = mimeType.name();
|
||||||
if (filesize <= MaxUploadPhotoSize && !voice) {
|
if (filemime != stickerMime) {
|
||||||
bool opaque = (filemime != stickerMime);
|
fullimage = Images::prepareOpaque(std_::move(fullimage));
|
||||||
fullimage = App::readImage(_content, 0, opaque, &animated);
|
|
||||||
}
|
}
|
||||||
if (filemime == "image/jpeg") {
|
if (filemime == "image/jpeg") {
|
||||||
filename = filedialogDefaultName(qsl("image"), qsl(".jpg"), QString(), true);
|
filename = filedialogDefaultName(qsl("photo"), qsl(".jpg"), QString(), true);
|
||||||
|
} else if (filemime == "image/png") {
|
||||||
|
filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
|
||||||
} else {
|
} else {
|
||||||
QString ext;
|
QString ext;
|
||||||
QStringList patterns = mimeType.globPatterns();
|
QStringList patterns = mimeType.globPatterns();
|
||||||
|
@ -253,9 +250,7 @@ void FileLoadTask::process() {
|
||||||
filename = filedialogDefaultName(qsl("file"), ext, QString(), true);
|
filename = filedialogDefaultName(qsl("file"), ext, QString(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!_image.isNull()) {
|
} else if (!fullimage.isNull()) {
|
||||||
_image = QImage();
|
|
||||||
|
|
||||||
filemime = mimeTypeForName("image/png").name();
|
filemime = mimeTypeForName("image/png").name();
|
||||||
filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
|
filename = filedialogDefaultName(qsl("image"), qsl(".png"), QString(), true);
|
||||||
{
|
{
|
||||||
|
@ -264,18 +259,11 @@ void FileLoadTask::process() {
|
||||||
}
|
}
|
||||||
filesize = _content.size();
|
filesize = _content.size();
|
||||||
|
|
||||||
if (fullimage.hasAlphaChannel()) {
|
fullimage = Images::prepareOpaque(std_::move(fullimage));
|
||||||
QImage solid(fullimage.width(), fullimage.height(), QImage::Format_ARGB32_Premultiplied);
|
|
||||||
solid.fill(st::imageBgTransparent->c);
|
|
||||||
{
|
|
||||||
QPainter(&solid).drawImage(0, 0, fullimage);
|
|
||||||
}
|
|
||||||
fullimage = solid;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_result->filesize = (int32)qMin(filesize, qint64(INT_MAX));
|
_result->filesize = (int32)qMin(filesize, qint64(INT_MAX));
|
||||||
|
|
||||||
if (!filesize || filesize > MaxUploadDocumentSize) {
|
if (!filesize || filesize > App::kFileSizeLimit) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +347,7 @@ void FileLoadTask::process() {
|
||||||
if (w < 20 * h && h < 20 * w) {
|
if (w < 20 * h && h < 20 * w) {
|
||||||
if (animated) {
|
if (animated) {
|
||||||
attributes.push_back(MTP_documentAttributeAnimated());
|
attributes.push_back(MTP_documentAttributeAnimated());
|
||||||
} else if (_type != PrepareDocument) {
|
} else if (_type != SendMediaType::File) {
|
||||||
auto thumb = (w > 100 || h > 100) ? App::pixmapFromImageInPlace(fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage);
|
auto thumb = (w > 100 || h > 100) ? App::pixmapFromImageInPlace(fullimage.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(fullimage);
|
||||||
photoThumbs.insert('s', thumb);
|
photoThumbs.insert('s', thumb);
|
||||||
photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));
|
photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));
|
||||||
|
@ -411,7 +399,7 @@ void FileLoadTask::process() {
|
||||||
} else {
|
} else {
|
||||||
document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_int(0), MTP_vector<MTPDocumentAttribute>(attributes));
|
document = MTP_document(MTP_long(_id), MTP_long(0), MTP_int(unixtime()), MTP_string(filemime), MTP_int(filesize), thumbSize, MTP_int(MTP::maindc()), MTP_int(0), MTP_vector<MTPDocumentAttribute>(attributes));
|
||||||
if (photo.type() == mtpc_photoEmpty) {
|
if (photo.type() == mtpc_photoEmpty) {
|
||||||
_type = PrepareDocument;
|
_type = SendMediaType::File;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,29 +423,12 @@ void FileLoadTask::process() {
|
||||||
|
|
||||||
void FileLoadTask::finish() {
|
void FileLoadTask::finish() {
|
||||||
if (!_result || !_result->filesize) {
|
if (!_result || !_result->filesize) {
|
||||||
if (_result) App::main()->onSendFileCancel(_result);
|
Ui::showLayer(new InformBox(lng_send_image_empty(lt_name, _filepath)), KeepOtherLayers);
|
||||||
Ui::showLayer(new InformBox(lang(lng_send_image_empty)), KeepOtherLayers);
|
} else if (_result->filesize == -1) { // dir
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_result->filesize == -1) { // dir
|
|
||||||
App::main()->onSendFileCancel(_result);
|
|
||||||
Ui::showLayer(new InformBox(lng_send_folder(lt_name, QFileInfo(_filepath).dir().dirName())), KeepOtherLayers);
|
Ui::showLayer(new InformBox(lng_send_folder(lt_name, QFileInfo(_filepath).dir().dirName())), KeepOtherLayers);
|
||||||
return;
|
} else if (_result->filesize > App::kFileSizeLimit) {
|
||||||
}
|
Ui::showLayer(new InformBox(lng_send_image_too_large(lt_name, _filepath)), KeepOtherLayers);
|
||||||
if (_result->filesize > MaxUploadDocumentSize) {
|
} else if (App::main()) {
|
||||||
App::main()->onSendFileCancel(_result);
|
App::main()->onSendFileConfirm(_result);
|
||||||
Ui::showLayer(new InformBox(lang(lng_send_image_too_large)), KeepOtherLayers);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (App::main()) {
|
|
||||||
bool confirm = (_confirm == FileLoadAlwaysConfirm) || (_result->photo.type() != mtpc_photoEmpty && _confirm != FileLoadNeverConfirm);
|
|
||||||
if (confirm) {
|
|
||||||
Ui::showLayer(new PhotoSendBox(_result), ShowAfterOtherLayers);
|
|
||||||
} else {
|
|
||||||
if (_result->type == PrepareAuto) {
|
|
||||||
_result->type = (_result->photo.type() != mtpc_photoEmpty) ? PreparePhoto : PrepareDocument;
|
|
||||||
}
|
|
||||||
App::main()->onSendFileConfirm(_result, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,39 +20,57 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
enum PrepareMediaType {
|
enum class CompressConfirm {
|
||||||
PrepareAuto,
|
Auto,
|
||||||
PreparePhoto,
|
Yes,
|
||||||
PrepareAudio,
|
No,
|
||||||
PrepareVideo,
|
None,
|
||||||
PrepareDocument,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ToPrepareMedia {
|
enum class SendMediaType {
|
||||||
ToPrepareMedia(const QString &file, const PeerId &peer, PrepareMediaType t, bool ctrlShiftEnter, MsgId replyTo) : id(rand_value<PhotoId>()), file(file), peer(peer), type(t), duration(0), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
|
Photo,
|
||||||
|
Audio,
|
||||||
|
File,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SendMediaPrepare {
|
||||||
|
SendMediaPrepare(const QString &file, const PeerId &peer, SendMediaType type, MsgId replyTo) : id(rand_value<PhotoId>()), file(file), peer(peer), type(type), replyTo(replyTo) {
|
||||||
}
|
}
|
||||||
ToPrepareMedia(const QImage &img, const PeerId &peer, PrepareMediaType t, bool ctrlShiftEnter, MsgId replyTo) : id(rand_value<PhotoId>()), img(img), peer(peer), type(t), duration(0), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
|
SendMediaPrepare(const QImage &img, const PeerId &peer, SendMediaType type, MsgId replyTo) : id(rand_value<PhotoId>()), img(img), peer(peer), type(type), replyTo(replyTo) {
|
||||||
}
|
}
|
||||||
ToPrepareMedia(const QByteArray &data, const PeerId &peer, PrepareMediaType t, bool ctrlShiftEnter, MsgId replyTo) : id(rand_value<PhotoId>()), data(data), peer(peer), type(t), duration(0), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
|
SendMediaPrepare(const QByteArray &data, const PeerId &peer, SendMediaType type, MsgId replyTo) : id(rand_value<PhotoId>()), data(data), peer(peer), type(type), replyTo(replyTo) {
|
||||||
}
|
}
|
||||||
ToPrepareMedia(const QByteArray &data, int32 duration, const PeerId &peer, PrepareMediaType t, bool ctrlShiftEnter, MsgId replyTo) : id(rand_value<PhotoId>()), data(data), peer(peer), type(t), duration(duration), ctrlShiftEnter(ctrlShiftEnter), replyTo(replyTo) {
|
SendMediaPrepare(const QByteArray &data, int duration, const PeerId &peer, SendMediaType type, MsgId replyTo) : id(rand_value<PhotoId>()), data(data), peer(peer), type(type), duration(duration), replyTo(replyTo) {
|
||||||
}
|
}
|
||||||
PhotoId id;
|
PhotoId id;
|
||||||
QString file;
|
QString file;
|
||||||
QImage img;
|
QImage img;
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
PeerId peer;
|
PeerId peer;
|
||||||
PrepareMediaType type;
|
SendMediaType type;
|
||||||
int32 duration;
|
int duration = 0;
|
||||||
bool ctrlShiftEnter;
|
|
||||||
MsgId replyTo;
|
MsgId replyTo;
|
||||||
};
|
|
||||||
typedef QList<ToPrepareMedia> ToPrepareMedias;
|
|
||||||
|
|
||||||
typedef QMap<int32, QByteArray> UploadFileParts;
|
};
|
||||||
struct ReadyLocalMedia {
|
using SendMediaPrepareList = QList<SendMediaPrepare>;
|
||||||
ReadyLocalMedia(PrepareMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &thumbId, const QString &thumbExt, const PeerId &peer, const MTPPhoto &photo, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg, bool ctrlShiftEnter, MsgId replyTo) :
|
|
||||||
replyTo(replyTo), type(type), file(file), filename(filename), filesize(filesize), data(data), thumbExt(thumbExt), id(id), thumbId(thumbId), peer(peer), photo(photo), document(document), photoThumbs(photoThumbs), ctrlShiftEnter(ctrlShiftEnter) {
|
using UploadFileParts = QMap<int, QByteArray>;
|
||||||
|
struct SendMediaReady {
|
||||||
|
SendMediaReady() = default; // temp
|
||||||
|
SendMediaReady(SendMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &thumbId, const QString &thumbExt, const PeerId &peer, const MTPPhoto &photo, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg, MsgId replyTo)
|
||||||
|
: replyTo(replyTo)
|
||||||
|
, type(type)
|
||||||
|
, file(file)
|
||||||
|
, filename(filename)
|
||||||
|
, filesize(filesize)
|
||||||
|
, data(data)
|
||||||
|
, thumbExt(thumbExt)
|
||||||
|
, id(id)
|
||||||
|
, thumbId(thumbId)
|
||||||
|
, peer(peer)
|
||||||
|
, photo(photo)
|
||||||
|
, document(document)
|
||||||
|
, photoThumbs(photoThumbs) {
|
||||||
if (!jpeg.isEmpty()) {
|
if (!jpeg.isEmpty()) {
|
||||||
int32 size = jpeg.size();
|
int32 size = jpeg.size();
|
||||||
for (int32 i = 0, part = 0; i < size; i += UploadPartSize, ++part) {
|
for (int32 i = 0, part = 0; i < size; i += UploadPartSize, ++part) {
|
||||||
|
@ -63,7 +81,7 @@ struct ReadyLocalMedia {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MsgId replyTo;
|
MsgId replyTo;
|
||||||
PrepareMediaType type;
|
SendMediaType type;
|
||||||
QString file, filename;
|
QString file, filename;
|
||||||
int32 filesize;
|
int32 filesize;
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
|
@ -77,58 +95,45 @@ struct ReadyLocalMedia {
|
||||||
UploadFileParts parts;
|
UploadFileParts parts;
|
||||||
QByteArray jpeg_md5;
|
QByteArray jpeg_md5;
|
||||||
|
|
||||||
bool ctrlShiftEnter;
|
|
||||||
QString caption;
|
QString caption;
|
||||||
|
|
||||||
ReadyLocalMedia() : type(PrepareAuto) { // temp
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Task {
|
class Task {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void process() = 0; // is executed in a separate thread
|
virtual void process() = 0; // is executed in a separate thread
|
||||||
virtual void finish() = 0; // is executed in the same as TaskQueue thread
|
virtual void finish() = 0; // is executed in the same as TaskQueue thread
|
||||||
virtual ~Task() {
|
virtual ~Task() = default;
|
||||||
}
|
|
||||||
|
|
||||||
TaskId id() const {
|
TaskId id() const {
|
||||||
return TaskId(this);
|
return static_cast<TaskId>(const_cast<Task*>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
typedef QSharedPointer<Task> TaskPtr;
|
using TaskPtr = QSharedPointer<Task>;
|
||||||
typedef QList<TaskPtr> TasksList;
|
using TasksList = QList<TaskPtr>;
|
||||||
|
|
||||||
class TaskQueueWorker;
|
class TaskQueueWorker;
|
||||||
class TaskQueue : public QObject {
|
class TaskQueue : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TaskQueue(QObject *parent, int32 stopTimeoutMs = 0); // <= 0 - never stop worker
|
TaskQueue(QObject *parent, int32 stopTimeoutMs = 0); // <= 0 - never stop worker
|
||||||
|
|
||||||
TaskId addTask(TaskPtr task);
|
TaskId addTask(TaskPtr task);
|
||||||
void addTasks(const TasksList &tasks);
|
void addTasks(const TasksList &tasks);
|
||||||
void cancelTask(TaskId id); // this task finish() won't be called
|
void cancelTask(TaskId id); // this task finish() won't be called
|
||||||
|
|
||||||
TaskId addTask(Task *task) {
|
|
||||||
return addTask(TaskPtr(task));
|
|
||||||
}
|
|
||||||
|
|
||||||
~TaskQueue();
|
~TaskQueue();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void taskAdded();
|
void taskAdded();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void onTaskProcessed();
|
void onTaskProcessed();
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class TaskQueueWorker;
|
friend class TaskQueueWorker;
|
||||||
|
|
||||||
void wakeThread();
|
void wakeThread();
|
||||||
|
@ -145,21 +150,18 @@ class TaskQueueWorker : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
TaskQueueWorker(TaskQueue *queue) : _queue(queue) {
|
||||||
TaskQueueWorker(TaskQueue *queue) : _queue(queue), _inTaskAdded(false) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void taskProcessed();
|
void taskProcessed();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void onTaskAdded();
|
void onTaskAdded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TaskQueue *_queue;
|
TaskQueue *_queue;
|
||||||
bool _inTaskAdded;
|
bool _inTaskAdded = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -175,28 +177,26 @@ struct FileLoadTo {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FileLoadResult {
|
struct FileLoadResult {
|
||||||
FileLoadResult(const uint64 &id, const FileLoadTo &to, const QString &originalText) : id(id)
|
FileLoadResult(const uint64 &id, const FileLoadTo &to, const QString &caption)
|
||||||
|
: id(id)
|
||||||
, to(to)
|
, to(to)
|
||||||
, type(PrepareAuto)
|
, caption(caption) {
|
||||||
, filesize(0)
|
|
||||||
, thumbId(0)
|
|
||||||
, originalText(originalText) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 id;
|
uint64 id;
|
||||||
FileLoadTo to;
|
FileLoadTo to;
|
||||||
PrepareMediaType type;
|
SendMediaType type;
|
||||||
QString filepath;
|
QString filepath;
|
||||||
QByteArray content;
|
QByteArray content;
|
||||||
|
|
||||||
QString filename;
|
QString filename;
|
||||||
QString filemime;
|
QString filemime;
|
||||||
int32 filesize;
|
int32 filesize = 0;
|
||||||
UploadFileParts fileparts;
|
UploadFileParts fileparts;
|
||||||
QByteArray filemd5;
|
QByteArray filemd5;
|
||||||
int32 partssize;
|
int32 partssize;
|
||||||
|
|
||||||
uint64 thumbId; // id is always file-id of media, thumbId is file-id of thumb ( == id for photos)
|
uint64 thumbId = 0; // id is always file-id of media, thumbId is file-id of thumb ( == id for photos)
|
||||||
QString thumbname;
|
QString thumbname;
|
||||||
UploadFileParts thumbparts;
|
UploadFileParts thumbparts;
|
||||||
QByteArray thumbmd5;
|
QByteArray thumbmd5;
|
||||||
|
@ -208,8 +208,6 @@ struct FileLoadResult {
|
||||||
PreparedPhotoThumbs photoThumbs;
|
PreparedPhotoThumbs photoThumbs;
|
||||||
QString caption;
|
QString caption;
|
||||||
|
|
||||||
QString originalText; // when pasted had an image mime save text mime here to insert if image send was cancelled
|
|
||||||
|
|
||||||
void setFileData(const QByteArray &filedata) {
|
void setFileData(const QByteArray &filedata) {
|
||||||
if (filedata.isEmpty()) {
|
if (filedata.isEmpty()) {
|
||||||
partssize = 0;
|
partssize = 0;
|
||||||
|
@ -235,19 +233,11 @@ struct FileLoadResult {
|
||||||
};
|
};
|
||||||
typedef QSharedPointer<FileLoadResult> FileLoadResultPtr;
|
typedef QSharedPointer<FileLoadResult> FileLoadResultPtr;
|
||||||
|
|
||||||
enum FileLoadForceConfirmType {
|
|
||||||
FileLoadNoForceConfirm,
|
|
||||||
FileLoadNeverConfirm,
|
|
||||||
FileLoadAlwaysConfirm,
|
|
||||||
};
|
|
||||||
|
|
||||||
class FileLoadTask : public Task {
|
class FileLoadTask : public Task {
|
||||||
public:
|
public:
|
||||||
|
FileLoadTask(const QString &filepath, SendMediaType type, const FileLoadTo &to, const QString &caption);
|
||||||
FileLoadTask(const QString &filepath, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm);
|
FileLoadTask(const QByteArray &content, const QImage &image, SendMediaType type, const FileLoadTo &to, const QString &caption);
|
||||||
FileLoadTask(const QByteArray &content, PrepareMediaType type, const FileLoadTo &to);
|
FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to, const QString &caption);
|
||||||
FileLoadTask(const QImage &image, PrepareMediaType type, const FileLoadTo &to, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, const QString &originalText = QString());
|
|
||||||
FileLoadTask(const QByteArray &voice, int32 duration, const VoiceWaveform &waveform, const FileLoadTo &to);
|
|
||||||
|
|
||||||
uint64 fileid() const {
|
uint64 fileid() const {
|
||||||
return _id;
|
return _id;
|
||||||
|
@ -257,17 +247,15 @@ public:
|
||||||
void finish();
|
void finish();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
uint64 _id;
|
uint64 _id;
|
||||||
FileLoadTo _to;
|
FileLoadTo _to;
|
||||||
QString _filepath;
|
QString _filepath;
|
||||||
QImage _image;
|
|
||||||
QByteArray _content;
|
QByteArray _content;
|
||||||
|
QImage _image;
|
||||||
int32 _duration = 0;
|
int32 _duration = 0;
|
||||||
VoiceWaveform _waveform;
|
VoiceWaveform _waveform;
|
||||||
PrepareMediaType _type;
|
SendMediaType _type;
|
||||||
FileLoadForceConfirmType _confirm = FileLoadNoForceConfirm;
|
QString _caption;
|
||||||
QString _originalText;
|
|
||||||
|
|
||||||
FileLoadResultPtr _result;
|
FileLoadResultPtr _result;
|
||||||
|
|
||||||
|
|
|
@ -1234,11 +1234,6 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
|
||||||
qint32 v;
|
qint32 v;
|
||||||
stream >> v;
|
stream >> v;
|
||||||
if (!_checkStreamStatus(stream)) return false;
|
if (!_checkStreamStatus(stream)) return false;
|
||||||
|
|
||||||
switch (v) {
|
|
||||||
case dbidaPhoto: cSetDefaultAttach(dbidaPhoto); break;
|
|
||||||
default: cSetDefaultAttach(dbidaDocument); break;
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case dbiNotifyView: {
|
case dbiNotifyView: {
|
||||||
|
@ -1631,7 +1626,6 @@ void _writeUserSettings() {
|
||||||
data.stream << quint32(dbiAdaptiveForWide) << qint32(Global::AdaptiveForWide() ? 1 : 0);
|
data.stream << quint32(dbiAdaptiveForWide) << qint32(Global::AdaptiveForWide() ? 1 : 0);
|
||||||
data.stream << quint32(dbiAutoLock) << qint32(Global::AutoLock());
|
data.stream << quint32(dbiAutoLock) << qint32(Global::AutoLock());
|
||||||
data.stream << quint32(dbiReplaceEmojis) << qint32(cReplaceEmojis() ? 1 : 0);
|
data.stream << quint32(dbiReplaceEmojis) << qint32(cReplaceEmojis() ? 1 : 0);
|
||||||
data.stream << quint32(dbiDefaultAttach) << qint32(cDefaultAttach());
|
|
||||||
data.stream << quint32(dbiSoundNotify) << qint32(Global::SoundNotify());
|
data.stream << quint32(dbiSoundNotify) << qint32(Global::SoundNotify());
|
||||||
data.stream << quint32(dbiIncludeMuted) << qint32(Global::IncludeMuted());
|
data.stream << quint32(dbiIncludeMuted) << qint32(Global::IncludeMuted());
|
||||||
data.stream << quint32(dbiShowingSavedGifs) << qint32(cShowingSavedGifs());
|
data.stream << quint32(dbiShowingSavedGifs) << qint32(cShowingSavedGifs());
|
||||||
|
@ -2738,7 +2732,7 @@ TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader) {
|
||||||
if (j == _imagesMap.cend() || !_localLoader) {
|
if (j == _imagesMap.cend() || !_localLoader) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return _localLoader->addTask(new ImageLoadTask(j->first, location, loader));
|
return _localLoader->addTask(MakeShared<ImageLoadTask>(j->first, location, loader));
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 hasImages() {
|
int32 hasImages() {
|
||||||
|
@ -2797,7 +2791,7 @@ TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader)
|
||||||
if (j == _stickerImagesMap.cend() || !_localLoader) {
|
if (j == _stickerImagesMap.cend() || !_localLoader) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return _localLoader->addTask(new StickerImageLoadTask(j->first, location, loader));
|
return _localLoader->addTask(MakeShared<StickerImageLoadTask>(j->first, location, loader));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool willStickerImageLoad(const StorageKey &location) {
|
bool willStickerImageLoad(const StorageKey &location) {
|
||||||
|
@ -2871,7 +2865,7 @@ TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader) {
|
||||||
if (j == _audiosMap.cend() || !_localLoader) {
|
if (j == _audiosMap.cend() || !_localLoader) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return _localLoader->addTask(new AudioLoadTask(j->first, location, loader));
|
return _localLoader->addTask(MakeShared<AudioLoadTask>(j->first, location, loader));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool copyAudio(const StorageKey &oldLocation, const StorageKey &newLocation) {
|
bool copyAudio(const StorageKey &oldLocation, const StorageKey &newLocation) {
|
||||||
|
@ -2986,7 +2980,7 @@ TaskId startWebFileLoad(const QString &url, webFileLoader *loader) {
|
||||||
if (j == _webFilesMap.cend() || !_localLoader) {
|
if (j == _webFilesMap.cend() || !_localLoader) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return _localLoader->addTask(new WebFileLoadTask(j->first, url, loader));
|
return _localLoader->addTask(MakeShared<WebFileLoadTask>(j->first, url, loader));
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 hasWebFiles() {
|
int32 hasWebFiles() {
|
||||||
|
@ -3062,7 +3056,7 @@ void countVoiceWaveform(DocumentData *document) {
|
||||||
if (_localLoader) {
|
if (_localLoader) {
|
||||||
voice->waveform.resize(1 + sizeof(TaskId));
|
voice->waveform.resize(1 + sizeof(TaskId));
|
||||||
voice->waveform[0] = -1; // counting
|
voice->waveform[0] = -1; // counting
|
||||||
TaskId taskId = _localLoader->addTask(new CountWaveformTask(document));
|
TaskId taskId = _localLoader->addTask(MakeShared<CountWaveformTask>(document));
|
||||||
memcpy(voice->waveform.data() + 1, &taskId, sizeof(taskId));
|
memcpy(voice->waveform.data() + 1, &taskId, sizeof(taskId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -450,8 +450,9 @@ void MainWidget::onShareContact(const PeerId &peer, UserData *contact) {
|
||||||
_history->onShareContact(peer, contact);
|
_history->onShareContact(peer, contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::onSendPaths(const PeerId &peer) {
|
bool MainWidget::onSendPaths(const PeerId &peer) {
|
||||||
_history->onSendPaths(peer);
|
Ui::showPeerHistory(peer, ShowAtTheEndMsgId);
|
||||||
|
return _history->confirmSendingFiles(cSendPaths());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data) {
|
void MainWidget::onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data) {
|
||||||
|
@ -463,7 +464,7 @@ void MainWidget::onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data)
|
||||||
onForward(peer, ForwardPressedMessage);
|
onForward(peer, ForwardPressedMessage);
|
||||||
} else {
|
} else {
|
||||||
Ui::showPeerHistory(peer, ShowAtTheEndMsgId);
|
Ui::showPeerHistory(peer, ShowAtTheEndMsgId);
|
||||||
_history->onFilesDrop(data);
|
_history->confirmSendingFiles(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1779,20 +1780,8 @@ void MainWidget::updateOnlineDisplay() {
|
||||||
_history->updateOnlineDisplay();
|
_history->updateOnlineDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::onSendFileConfirm(const FileLoadResultPtr &file, bool ctrlShiftEnter) {
|
void MainWidget::onSendFileConfirm(const FileLoadResultPtr &file) {
|
||||||
_history->confirmSendFile(file, ctrlShiftEnter);
|
_history->sendFileConfirmed(file);
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::onSendFileCancel(const FileLoadResultPtr &file) {
|
|
||||||
_history->cancelSendFile(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::onShareContactConfirm(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, bool ctrlShiftEnter) {
|
|
||||||
_history->confirmShareContact(phone, fname, lname, replyTo, ctrlShiftEnter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::onShareContactCancel() {
|
|
||||||
_history->cancelShareContact();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWidget::onSendSticker(DocumentData *document) {
|
bool MainWidget::onSendSticker(DocumentData *document) {
|
||||||
|
|
|
@ -212,10 +212,7 @@ public:
|
||||||
QRect historyRect() const;
|
QRect historyRect() const;
|
||||||
QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms);
|
QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms);
|
||||||
|
|
||||||
void onSendFileConfirm(const FileLoadResultPtr &file, bool ctrlShiftEnter);
|
void onSendFileConfirm(const FileLoadResultPtr &file);
|
||||||
void onSendFileCancel(const FileLoadResultPtr &file);
|
|
||||||
void onShareContactConfirm(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, bool ctrlShiftEnter);
|
|
||||||
void onShareContactCancel();
|
|
||||||
bool onSendSticker(DocumentData *sticker);
|
bool onSendSticker(DocumentData *sticker);
|
||||||
|
|
||||||
void destroyData();
|
void destroyData();
|
||||||
|
@ -243,7 +240,7 @@ public:
|
||||||
bool onShareUrl(const PeerId &peer, const QString &url, const QString &text);
|
bool onShareUrl(const PeerId &peer, const QString &url, const QString &text);
|
||||||
bool onInlineSwitchChosen(const PeerId &peer, const QString &botAndQuery);
|
bool onInlineSwitchChosen(const PeerId &peer, const QString &botAndQuery);
|
||||||
void onShareContact(const PeerId &peer, UserData *contact);
|
void onShareContact(const PeerId &peer, UserData *contact);
|
||||||
void onSendPaths(const PeerId &peer);
|
bool onSendPaths(const PeerId &peer);
|
||||||
void onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data);
|
void onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data);
|
||||||
bool selectingPeer(bool withConfirm = false);
|
bool selectingPeer(bool withConfirm = false);
|
||||||
bool selectingPeerForInlineSwitch();
|
bool selectingPeerForInlineSwitch();
|
||||||
|
|
|
@ -413,6 +413,9 @@ void MainWindow::showMainMenu() {
|
||||||
void MainWindow::ui_hideSettingsAndLayer(ShowLayerOptions options) {
|
void MainWindow::ui_hideSettingsAndLayer(ShowLayerOptions options) {
|
||||||
if (_layerBg) {
|
if (_layerBg) {
|
||||||
_layerBg->hideAll();
|
_layerBg->hideAll();
|
||||||
|
if (options.testFlag(ForceFastShowLayer)) {
|
||||||
|
_layerBg.destroyDelayed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1412,7 +1415,7 @@ QImage MainWindow::iconWithCounter(int size, int count, const style::color &bg,
|
||||||
void MainWindow::sendPaths() {
|
void MainWindow::sendPaths() {
|
||||||
if (App::passcoded()) return;
|
if (App::passcoded()) return;
|
||||||
hideMediaview();
|
hideMediaview();
|
||||||
Ui::hideSettingsAndLayer();
|
Ui::hideSettingsAndLayer(true);
|
||||||
if (_main) {
|
if (_main) {
|
||||||
_main->activate();
|
_main->activate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ QPixmap _prepareFrame(const FrameRequest &request, const QImage &original, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (request.radius != ImageRoundRadius::None) {
|
if (request.radius != ImageRoundRadius::None) {
|
||||||
imageRound(cache, request.radius, request.corners);
|
Images::prepareRound(cache, request.radius, request.corners);
|
||||||
}
|
}
|
||||||
return QPixmap::fromImage(cache, Qt::ColorOnly);
|
return QPixmap::fromImage(cache, Qt::ColorOnly);
|
||||||
}
|
}
|
||||||
|
|
|
@ -491,7 +491,7 @@ void MediaView::step_radial(uint64 ms, bool timer) {
|
||||||
if (timer && (wasAnimating || _radial.animating())) {
|
if (timer && (wasAnimating || _radial.animating())) {
|
||||||
update(radialRect());
|
update(radialRect());
|
||||||
}
|
}
|
||||||
if (_doc && _doc->loaded() && _doc->size < MediaViewImageSizeLimit && (!_radial.animating() || _doc->isAnimation() || _doc->isVideo())) {
|
if (_doc && _doc->loaded() && _doc->size < App::kImageSizeLimit && (!_radial.animating() || _doc->isAnimation() || _doc->isVideo())) {
|
||||||
if (_doc->isVideo()) {
|
if (_doc->isVideo()) {
|
||||||
_autoplayVideoDocument = _doc;
|
_autoplayVideoDocument = _doc;
|
||||||
}
|
}
|
||||||
|
@ -1329,10 +1329,10 @@ void MediaView::initAnimation() {
|
||||||
} else if (_doc->dimensions.width() && _doc->dimensions.height()) {
|
} else if (_doc->dimensions.width() && _doc->dimensions.height()) {
|
||||||
int w = _doc->dimensions.width();
|
int w = _doc->dimensions.width();
|
||||||
int h = _doc->dimensions.height();
|
int h = _doc->dimensions.height();
|
||||||
_current = _doc->thumb->pixNoCache(w, h, ImagePixOption::Smooth | ImagePixOption::Blurred, w / cIntRetinaFactor(), h / cIntRetinaFactor());
|
_current = _doc->thumb->pixNoCache(w, h, Images::Option::Smooth | Images::Option::Blurred, w / cIntRetinaFactor(), h / cIntRetinaFactor());
|
||||||
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
|
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
|
||||||
} else {
|
} else {
|
||||||
_current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixOption::Smooth | ImagePixOption::Blurred, st::mediaviewFileIconSize, st::mediaviewFileIconSize);
|
_current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), Images::Option::Smooth | Images::Option::Blurred, st::mediaviewFileIconSize, st::mediaviewFileIconSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,10 +1345,10 @@ void MediaView::createClipReader() {
|
||||||
if (_doc->dimensions.width() && _doc->dimensions.height()) {
|
if (_doc->dimensions.width() && _doc->dimensions.height()) {
|
||||||
int w = _doc->dimensions.width();
|
int w = _doc->dimensions.width();
|
||||||
int h = _doc->dimensions.height();
|
int h = _doc->dimensions.height();
|
||||||
_current = _doc->thumb->pixNoCache(w, h, ImagePixOption::Smooth | ImagePixOption::Blurred, w / cIntRetinaFactor(), h / cIntRetinaFactor());
|
_current = _doc->thumb->pixNoCache(w, h, Images::Option::Smooth | Images::Option::Blurred, w / cIntRetinaFactor(), h / cIntRetinaFactor());
|
||||||
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
|
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
|
||||||
} else {
|
} else {
|
||||||
_current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixOption::Smooth | ImagePixOption::Blurred, st::mediaviewFileIconSize, st::mediaviewFileIconSize);
|
_current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), Images::Option::Smooth | Images::Option::Blurred, st::mediaviewFileIconSize, st::mediaviewFileIconSize);
|
||||||
}
|
}
|
||||||
auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif;
|
auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif;
|
||||||
_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) {
|
_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) {
|
||||||
|
@ -1543,17 +1543,17 @@ void MediaView::paintEvent(QPaintEvent *e) {
|
||||||
int32 w = _width * cIntRetinaFactor();
|
int32 w = _width * cIntRetinaFactor();
|
||||||
if (_full <= 0 && _photo->loaded()) {
|
if (_full <= 0 && _photo->loaded()) {
|
||||||
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
|
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
|
||||||
_current = _photo->full->pixNoCache(w, h, ImagePixOption::Smooth);
|
_current = _photo->full->pixNoCache(w, h, Images::Option::Smooth);
|
||||||
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
|
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
|
||||||
_full = 1;
|
_full = 1;
|
||||||
} else if (_full < 0 && _photo->medium->loaded()) {
|
} else if (_full < 0 && _photo->medium->loaded()) {
|
||||||
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
|
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
|
||||||
_current = _photo->medium->pixNoCache(w, h, ImagePixOption::Smooth | ImagePixOption::Blurred);
|
_current = _photo->medium->pixNoCache(w, h, Images::Option::Smooth | Images::Option::Blurred);
|
||||||
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
|
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
|
||||||
_full = 0;
|
_full = 0;
|
||||||
} else if (_current.isNull() && _photo->thumb->loaded()) {
|
} else if (_current.isNull() && _photo->thumb->loaded()) {
|
||||||
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
|
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
|
||||||
_current = _photo->thumb->pixNoCache(w, h, ImagePixOption::Smooth | ImagePixOption::Blurred);
|
_current = _photo->thumb->pixNoCache(w, h, Images::Option::Smooth | Images::Option::Blurred);
|
||||||
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
|
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
|
||||||
} else if (_current.isNull()) {
|
} else if (_current.isNull()) {
|
||||||
_current = _photo->thumb->pix();
|
_current = _photo->thumb->pix();
|
||||||
|
|
|
@ -94,7 +94,7 @@ enum LocalLoadStatus {
|
||||||
LocalFailed,
|
LocalFailed,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void *TaskId; // no interface, just id
|
using TaskId = void*; // no interface, just id
|
||||||
|
|
||||||
enum LoadFromCloudSetting {
|
enum LoadFromCloudSetting {
|
||||||
LoadFromCloudOrLocal,
|
LoadFromCloudOrLocal,
|
||||||
|
|
|
@ -827,17 +827,6 @@ protected:
|
||||||
typedef void (*MTPStateChangedHandler)(int32 dcId, int32 state);
|
typedef void (*MTPStateChangedHandler)(int32 dcId, int32 state);
|
||||||
typedef void(*MTPSessionResetHandler)(int32 dcId);
|
typedef void(*MTPSessionResetHandler)(int32 dcId);
|
||||||
|
|
||||||
template <typename FunctionType>
|
|
||||||
struct LambdaUniqueHelper;
|
|
||||||
|
|
||||||
template <typename Lambda, typename R, typename ...Args>
|
|
||||||
struct LambdaUniqueHelper<R(Lambda::*)(Args...) const> {
|
|
||||||
using UniqueType = base::lambda<R(Args...)>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename FunctionType>
|
|
||||||
using LambdaGetUnique = typename LambdaUniqueHelper<FunctionType>::UniqueType;
|
|
||||||
|
|
||||||
template <typename Base, typename FunctionType>
|
template <typename Base, typename FunctionType>
|
||||||
class RPCHandlerImplementation : public Base {
|
class RPCHandlerImplementation : public Base {
|
||||||
protected:
|
protected:
|
||||||
|
@ -948,7 +937,7 @@ inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda<R(mtpRequestId)
|
||||||
|
|
||||||
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
|
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
|
||||||
RPCDoneHandlerPtr rpcDone(Lambda &&lambda) {
|
RPCDoneHandlerPtr rpcDone(Lambda &&lambda) {
|
||||||
return rpcDone_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
|
return rpcDone_lambda_wrap_helper(base::lambda_type<Lambda>(std_::move(lambda)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FunctionType>
|
template <typename FunctionType>
|
||||||
|
@ -1008,5 +997,5 @@ inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda<bool(mtpRequest
|
||||||
|
|
||||||
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
|
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
|
||||||
RPCFailHandlerPtr rpcFail(Lambda &&lambda) {
|
RPCFailHandlerPtr rpcFail(Lambda &&lambda) {
|
||||||
return rpcFail_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
|
return rpcFail_lambda_wrap_helper(base::lambda_type<Lambda>(std_::move(lambda)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,9 +240,9 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
||||||
|
|
||||||
int32 size = _width * cIntRetinaFactor();
|
int32 size = _width * cIntRetinaFactor();
|
||||||
if (_goodLoaded || _data->thumb->loaded()) {
|
if (_goodLoaded || _data->thumb->loaded()) {
|
||||||
QImage img = (_data->loaded() ? _data->full : (_data->medium->loaded() ? _data->medium : _data->thumb))->pix().toImage();
|
auto img = (_data->loaded() ? _data->full : (_data->medium->loaded() ? _data->medium : _data->thumb))->pix().toImage();
|
||||||
if (!_goodLoaded) {
|
if (!_goodLoaded) {
|
||||||
img = imageBlur(img);
|
img = Images::prepareBlur(img);
|
||||||
}
|
}
|
||||||
if (img.width() == img.height()) {
|
if (img.width() == img.height()) {
|
||||||
if (img.width() != size) {
|
if (img.width() != size) {
|
||||||
|
@ -337,7 +337,7 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
||||||
|
|
||||||
if (_thumbLoaded && !_data->thumb->isNull()) {
|
if (_thumbLoaded && !_data->thumb->isNull()) {
|
||||||
int32 size = _width * cIntRetinaFactor();
|
int32 size = _width * cIntRetinaFactor();
|
||||||
QImage img = imageBlur(_data->thumb->pix().toImage());
|
auto img = Images::prepareBlur(_data->thumb->pix().toImage());
|
||||||
if (img.width() == img.height()) {
|
if (img.width() == img.height()) {
|
||||||
if (img.width() != size) {
|
if (img.width() != size) {
|
||||||
img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||||
|
@ -797,8 +797,8 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
|
||||||
if (_data->thumb->loaded()) {
|
if (_data->thumb->loaded()) {
|
||||||
if (_thumb.isNull() || loaded != _thumbForLoaded) {
|
if (_thumb.isNull() || loaded != _thumbForLoaded) {
|
||||||
_thumbForLoaded = loaded;
|
_thumbForLoaded = loaded;
|
||||||
auto options = ImagePixOption::Smooth | ImagePixOption::None;
|
auto options = Images::Option::Smooth | Images::Option::None;
|
||||||
if (!_thumbForLoaded) options |= ImagePixOption::Blurred;
|
if (!_thumbForLoaded) options |= Images::Option::Blurred;
|
||||||
_thumb = _data->thumb->pixNoCache(_thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize);
|
_thumb = _data->thumb->pixNoCache(_thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize);
|
||||||
}
|
}
|
||||||
p.drawPixmap(rthumb.topLeft(), _thumb);
|
p.drawPixmap(rthumb.topLeft(), _thumb);
|
||||||
|
|
|
@ -36,6 +36,10 @@ bool Supported();
|
||||||
|
|
||||||
bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile);
|
bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile);
|
||||||
|
|
||||||
|
inline QString UrlToLocal(const QUrl &url) {
|
||||||
|
return url.toLocalFile();
|
||||||
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// This is a patched copy of qgtk2 theme plugin.
|
// This is a patched copy of qgtk2 theme plugin.
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Platform {
|
||||||
|
namespace FileDialog {
|
||||||
|
|
||||||
|
inline bool Supported() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString UrlToLocal(const QUrl &url);
|
||||||
|
|
||||||
|
} // namespace FileDialog
|
||||||
|
} // namespace Platform
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "platform/mac/file_dialog_mac.h"
|
||||||
|
|
||||||
|
#include "platform/mac/mac_utilities.h"
|
||||||
|
|
||||||
|
#include <Cocoa/Cocoa.h>
|
||||||
|
#include <CoreFoundation/CFURL.h>
|
||||||
|
|
||||||
|
namespace Platform {
|
||||||
|
namespace FileDialog {
|
||||||
|
|
||||||
|
QString UrlToLocal(const QUrl &url) {
|
||||||
|
auto result = url.toLocalFile();
|
||||||
|
if (result.startsWith(qsl("/.file/id="))) {
|
||||||
|
NSString *nsurl = [[[NSURL URLWithString: [NSString stringWithUTF8String: (qsl("file://") + result).toUtf8().constData()]] filePathURL] path];
|
||||||
|
if (!nsurl) return QString();
|
||||||
|
|
||||||
|
return NS2QString(nsurl);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace FileDialog
|
||||||
|
} // namespace Platform
|
|
@ -22,17 +22,28 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
|
|
||||||
#if defined Q_OS_LINUX
|
#ifdef Q_OS_MAC
|
||||||
|
#include "platform/mac/file_dialog_mac.h"
|
||||||
|
#elif defined Q_OS_LINUX // Q_OS_MAC
|
||||||
#include "platform/linux/file_dialog_linux.h"
|
#include "platform/linux/file_dialog_linux.h"
|
||||||
#else // Q_OS_LINUX
|
#elif defined Q_OS_WINRT || defined Q_OS_WIN // Q_OS_MAC || Q_OS_LINUX
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace FileDialog {
|
namespace FileDialog {
|
||||||
|
|
||||||
inline bool Supported() {
|
inline bool Supported() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile) {
|
inline bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QString UrlToLocal(const QUrl &url) {
|
||||||
|
return url.toLocalFile();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace FileDialog
|
} // namespace FileDialog
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
#endif // else for Q_OS_LINUX
|
|
||||||
|
#endif // Q_OS_MAC || Q_OS_LINUX || Q_OS_WINRT || Q_OS_WIN
|
||||||
|
|
|
@ -26,7 +26,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "platform/mac/window_title_mac.h"
|
#include "platform/mac/window_title_mac.h"
|
||||||
#elif defined Q_OS_WIN // Q_OS_MAC
|
#elif defined Q_OS_WIN // Q_OS_MAC
|
||||||
#include "platform/win/window_title_win.h"
|
#include "platform/win/window_title_win.h"
|
||||||
#elif defined Q_OS_WINRT || defined Q_OS_LINUX
|
#elif defined Q_OS_WINRT || defined Q_OS_LINUX // Q_OS_MAC || Q_OS_WIN
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
inline Window::TitleWidget *CreateTitleWidget(QWidget *parent) {
|
inline Window::TitleWidget *CreateTitleWidget(QWidget *parent) {
|
||||||
|
@ -34,4 +35,5 @@ inline Window::TitleWidget *CreateTitleWidget(QWidget *parent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
||||||
#endif // Q_OS_MAC || Q_OS_WIN || Q_OS_WINRT || Q_OS_LINUX
|
#endif // Q_OS_MAC || Q_OS_WIN || Q_OS_WINRT || Q_OS_LINUX
|
||||||
|
|
|
@ -37,6 +37,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
|
#include "platform/platform_file_dialog.h"
|
||||||
|
|
||||||
namespace Profile {
|
namespace Profile {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -251,13 +252,12 @@ bool CoverWidget::mimeDataHasImage(const QMimeData *mimeData) const {
|
||||||
auto &url = urls.at(0);
|
auto &url = urls.at(0);
|
||||||
if (!url.isLocalFile()) return false;
|
if (!url.isLocalFile()) return false;
|
||||||
|
|
||||||
auto file = psConvertFileUrl(url);
|
auto file = Platform::FileDialog::UrlToLocal(url);
|
||||||
|
|
||||||
QFileInfo info(file);
|
QFileInfo info(file);
|
||||||
if (info.isDir()) return false;
|
if (info.isDir()) return false;
|
||||||
|
|
||||||
quint64 s = info.size();
|
if (info.size() > App::kImageSizeLimit) return false;
|
||||||
if (s >= MaxUploadDocumentSize) return false;
|
|
||||||
|
|
||||||
for (auto &ext : cImgExtensions()) {
|
for (auto &ext : cImgExtensions()) {
|
||||||
if (file.endsWith(ext, Qt::CaseInsensitive)) {
|
if (file.endsWith(ext, Qt::CaseInsensitive)) {
|
||||||
|
@ -305,7 +305,7 @@ void CoverWidget::dropEvent(QDropEvent *e) {
|
||||||
if (urls.size() == 1) {
|
if (urls.size() == 1) {
|
||||||
auto &url = urls.at(0);
|
auto &url = urls.at(0);
|
||||||
if (url.isLocalFile()) {
|
if (url.isLocalFile()) {
|
||||||
img = App::readImage(psConvertFileUrl(url));
|
img = App::readImage(Platform::FileDialog::UrlToLocal(url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -483,7 +483,7 @@ void CoverWidget::onSetPhoto() {
|
||||||
QStringList imgExtensions(cImgExtensions());
|
QStringList imgExtensions(cImgExtensions());
|
||||||
QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter());
|
QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter());
|
||||||
|
|
||||||
_setPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_images), filter);
|
_setPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_image), filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update) {
|
void CoverWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update) {
|
||||||
|
|
|
@ -74,9 +74,6 @@ QAbstractNativeEventFilter *psNativeEventFilter();
|
||||||
void psNewVersion();
|
void psNewVersion();
|
||||||
|
|
||||||
void psUpdateOverlayed(QWidget *widget);
|
void psUpdateOverlayed(QWidget *widget);
|
||||||
inline QString psConvertFileUrl(const QUrl &url) {
|
|
||||||
return url.toLocalFile();
|
|
||||||
}
|
|
||||||
inline QByteArray psDownloadPathBookmark(const QString &path) {
|
inline QByteArray psDownloadPathBookmark(const QString &path) {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
|
@ -443,14 +443,6 @@ void psSendToMenu(bool send, bool silent) {
|
||||||
void psUpdateOverlayed(QWidget *widget) {
|
void psUpdateOverlayed(QWidget *widget) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString psConvertFileUrl(const QUrl &url) {
|
|
||||||
auto urlString = url.toLocalFile();
|
|
||||||
if (urlString.startsWith(qsl("/.file/id="))) {
|
|
||||||
return objc_convertFileUrl(urlString);
|
|
||||||
}
|
|
||||||
return urlString;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psDownloadPathEnableAccess() {
|
void psDownloadPathEnableAccess() {
|
||||||
objc_downloadPathEnableAccess(Global::DownloadPathBookmark());
|
objc_downloadPathEnableAccess(Global::DownloadPathBookmark());
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,6 @@ QAbstractNativeEventFilter *psNativeEventFilter();
|
||||||
void psNewVersion();
|
void psNewVersion();
|
||||||
|
|
||||||
void psUpdateOverlayed(QWidget *widget);
|
void psUpdateOverlayed(QWidget *widget);
|
||||||
QString psConvertFileUrl(const QUrl &url);
|
|
||||||
|
|
||||||
void psDownloadPathEnableAccess();
|
void psDownloadPathEnableAccess();
|
||||||
QByteArray psDownloadPathBookmark(const QString &path);
|
QByteArray psDownloadPathBookmark(const QString &path);
|
||||||
|
|
|
@ -53,7 +53,6 @@ QString objc_appDataPath();
|
||||||
QString objc_downloadPath();
|
QString objc_downloadPath();
|
||||||
QString objc_currentCountry();
|
QString objc_currentCountry();
|
||||||
QString objc_currentLang();
|
QString objc_currentLang();
|
||||||
QString objc_convertFileUrl(const QString &url);
|
|
||||||
QByteArray objc_downloadPathBookmark(const QString &path);
|
QByteArray objc_downloadPathBookmark(const QString &path);
|
||||||
QByteArray objc_pathBookmark(const QString &path);
|
QByteArray objc_pathBookmark(const QString &path);
|
||||||
void objc_downloadPathEnableAccess(const QByteArray &bookmark);
|
void objc_downloadPathEnableAccess(const QByteArray &bookmark);
|
||||||
|
|
|
@ -999,13 +999,6 @@ QString objc_currentLang() {
|
||||||
return currentLang ? NS2QString(currentLang) : QString();
|
return currentLang ? NS2QString(currentLang) : QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString objc_convertFileUrl(const QString &url) {
|
|
||||||
NSString *nsurl = [[[NSURL URLWithString: [NSString stringWithUTF8String: (qsl("file://") + url).toUtf8().constData()]] filePathURL] path];
|
|
||||||
if (!nsurl) return QString();
|
|
||||||
|
|
||||||
return NS2QString(nsurl);
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray objc_downloadPathBookmark(const QString &path) {
|
QByteArray objc_downloadPathBookmark(const QString &path) {
|
||||||
#ifndef OS_MAC_STORE
|
#ifndef OS_MAC_STORE
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
|
|
|
@ -74,9 +74,6 @@ QAbstractNativeEventFilter *psNativeEventFilter();
|
||||||
void psNewVersion();
|
void psNewVersion();
|
||||||
|
|
||||||
void psUpdateOverlayed(TWidget *widget);
|
void psUpdateOverlayed(TWidget *widget);
|
||||||
inline QString psConvertFileUrl(const QUrl &url) {
|
|
||||||
return url.toLocalFile();
|
|
||||||
}
|
|
||||||
inline QByteArray psDownloadPathBookmark(const QString &path) {
|
inline QByteArray psDownloadPathBookmark(const QString &path) {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,6 @@ bool gRestartingUpdate = false, gRestarting = false, gRestartingToSettings = fal
|
||||||
int32 gLastUpdateCheck = 0;
|
int32 gLastUpdateCheck = 0;
|
||||||
bool gNoStartUpdate = false;
|
bool gNoStartUpdate = false;
|
||||||
bool gStartToSettings = false;
|
bool gStartToSettings = false;
|
||||||
DBIDefaultAttach gDefaultAttach = dbidaDocument;
|
|
||||||
bool gReplaceEmojis = true;
|
bool gReplaceEmojis = true;
|
||||||
|
|
||||||
bool gCtrlEnter = false;
|
bool gCtrlEnter = false;
|
||||||
|
|
|
@ -102,7 +102,6 @@ struct TWindowPos {
|
||||||
DeclareSetting(TWindowPos, WindowPos);
|
DeclareSetting(TWindowPos, WindowPos);
|
||||||
DeclareSetting(bool, SupportTray);
|
DeclareSetting(bool, SupportTray);
|
||||||
DeclareSetting(DBIWorkMode, WorkMode);
|
DeclareSetting(DBIWorkMode, WorkMode);
|
||||||
DeclareSetting(DBIDefaultAttach, DefaultAttach);
|
|
||||||
DeclareSetting(bool, SeenTrayTooltip);
|
DeclareSetting(bool, SeenTrayTooltip);
|
||||||
DeclareSetting(bool, RestartingUpdate);
|
DeclareSetting(bool, RestartingUpdate);
|
||||||
DeclareSetting(bool, Restarting);
|
DeclareSetting(bool, Restarting);
|
||||||
|
|
|
@ -151,7 +151,7 @@ void BackgroundRow::updateImage() {
|
||||||
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||||
p.drawPixmap(0, 0, st::settingsBackgroundSize, st::settingsBackgroundSize, pix, sx, sy, s, s);
|
p.drawPixmap(0, 0, st::settingsBackgroundSize, st::settingsBackgroundSize, pix, sx, sy, s, s);
|
||||||
}
|
}
|
||||||
imageRound(back, ImageRoundRadius::Small);
|
Images::prepareRound(back, ImageRoundRadius::Small);
|
||||||
_background = App::pixmapFromImageInPlace(std_::move(back));
|
_background = App::pixmapFromImageInPlace(std_::move(back));
|
||||||
_background.setDevicePixelRatio(cRetinaFactor());
|
_background.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ void BackgroundWidget::onChooseFromFile() {
|
||||||
filters.push_back(qsl("Theme files (*.tdesktop-theme)"));
|
filters.push_back(qsl("Theme files (*.tdesktop-theme)"));
|
||||||
filters.push_back(filedialogAllFilesFilter());
|
filters.push_back(filedialogAllFilesFilter());
|
||||||
|
|
||||||
_chooseFromFileQueryId = FileDialog::queryReadFile(lang(lng_choose_images), filters.join(qsl(";;")));
|
_chooseFromFileQueryId = FileDialog::queryReadFile(lang(lng_choose_image), filters.join(qsl(";;")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update) {
|
void BackgroundWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update) {
|
||||||
|
|
|
@ -34,6 +34,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
#include "styles/style_settings.h"
|
#include "styles/style_settings.h"
|
||||||
#include "styles/style_profile.h" // for divider
|
#include "styles/style_profile.h" // for divider
|
||||||
|
#include "platform/platform_file_dialog.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
|
@ -184,13 +185,12 @@ bool CoverWidget::mimeDataHasImage(const QMimeData *mimeData) const {
|
||||||
auto &url = urls.at(0);
|
auto &url = urls.at(0);
|
||||||
if (!url.isLocalFile()) return false;
|
if (!url.isLocalFile()) return false;
|
||||||
|
|
||||||
auto file = psConvertFileUrl(url);
|
auto file = Platform::FileDialog::UrlToLocal(url);
|
||||||
|
|
||||||
QFileInfo info(file);
|
QFileInfo info(file);
|
||||||
if (info.isDir()) return false;
|
if (info.isDir()) return false;
|
||||||
|
|
||||||
quint64 s = info.size();
|
if (info.size() > App::kImageSizeLimit) return false;
|
||||||
if (s >= MaxUploadDocumentSize) return false;
|
|
||||||
|
|
||||||
for (auto &ext : cImgExtensions()) {
|
for (auto &ext : cImgExtensions()) {
|
||||||
if (file.endsWith(ext, Qt::CaseInsensitive)) {
|
if (file.endsWith(ext, Qt::CaseInsensitive)) {
|
||||||
|
@ -233,7 +233,7 @@ void CoverWidget::dropEvent(QDropEvent *e) {
|
||||||
if (urls.size() == 1) {
|
if (urls.size() == 1) {
|
||||||
auto &url = urls.at(0);
|
auto &url = urls.at(0);
|
||||||
if (url.isLocalFile()) {
|
if (url.isLocalFile()) {
|
||||||
img = App::readImage(psConvertFileUrl(url));
|
img = App::readImage(Platform::FileDialog::UrlToLocal(url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,10 +294,10 @@ void CoverWidget::refreshStatusText() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverWidget::onSetPhoto() {
|
void CoverWidget::onSetPhoto() {
|
||||||
QStringList imgExtensions(cImgExtensions());
|
auto imageExtensions = cImgExtensions();
|
||||||
QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter());
|
auto filter = qsl("Image files (*") + imageExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter();
|
||||||
|
|
||||||
_setPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_images), filter);
|
_setPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_image), filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoverWidget::onEditName() {
|
void CoverWidget::onEditName() {
|
||||||
|
|
|
@ -1033,7 +1033,7 @@ void DocumentOpenClickHandler::doOpen(DocumentData *data, HistoryItem *context,
|
||||||
psOpenFile(filepath);
|
psOpenFile(filepath);
|
||||||
}
|
}
|
||||||
if (App::main()) App::main()->mediaMarkRead(data);
|
if (App::main()) App::main()->mediaMarkRead(data);
|
||||||
} else if (data->size < MediaViewImageSizeLimit) {
|
} else if (data->size < App::kImageSizeLimit) {
|
||||||
if (!data->data().isEmpty() && playAnimation) {
|
if (!data->data().isEmpty() && playAnimation) {
|
||||||
if (action == ActionOnLoadPlayInline && context && context->getMedia()) {
|
if (action == ActionOnLoadPlayInline && context && context->getMedia()) {
|
||||||
context->getMedia()->playInline(context);
|
context->getMedia()->playInline(context);
|
||||||
|
@ -1284,7 +1284,7 @@ void DocumentData::performActionOnLoad() {
|
||||||
auto loc = location(true);
|
auto loc = location(true);
|
||||||
auto already = loc.name();
|
auto already = loc.name();
|
||||||
auto item = _actionOnLoadMsgId.msg ? App::histItemById(_actionOnLoadMsgId) : nullptr;
|
auto item = _actionOnLoadMsgId.msg ? App::histItemById(_actionOnLoadMsgId) : nullptr;
|
||||||
bool showImage = !isVideo() && (size < MediaViewImageSizeLimit);
|
bool showImage = !isVideo() && (size < App::kImageSizeLimit);
|
||||||
bool playVoice = voice() && audioPlayer() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen);
|
bool playVoice = voice() && audioPlayer() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen);
|
||||||
bool playMusic = song() && audioPlayer() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen);
|
bool playMusic = song() && audioPlayer() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen);
|
||||||
bool playAnimation = isAnimation() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen) && showImage && item && item->getMedia();
|
bool playAnimation = isAnimation() && (_actionOnLoad == ActionOnLoadPlayInline || _actionOnLoad == ActionOnLoadOpen) && showImage && item && item->getMedia();
|
||||||
|
|
|
@ -64,7 +64,7 @@ void NewAvatarButton::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
void NewAvatarButton::setImage(const QImage &image) {
|
void NewAvatarButton::setImage(const QImage &image) {
|
||||||
auto small = image.scaled(size() * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
auto small = image.scaled(size() * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||||
imageCircle(small);
|
Images::prepareCircle(small);
|
||||||
_image = App::pixmapFromImageInPlace(std_::move(small));
|
_image = App::pixmapFromImageInPlace(std_::move(small));
|
||||||
_image.setDevicePixelRatio(cRetinaFactor());
|
_image.setDevicePixelRatio(cRetinaFactor());
|
||||||
update();
|
update();
|
||||||
|
|
|
@ -193,7 +193,7 @@ CountrySelectBox::CountrySelectBox() : ItemListBox(st::countriesScroll, st::boxW
|
||||||
connect(_inner, SIGNAL(mustScrollTo(int, int)), scrollArea(), SLOT(scrollToY(int, int)));
|
connect(_inner, SIGNAL(mustScrollTo(int, int)), scrollArea(), SLOT(scrollToY(int, int)));
|
||||||
connect(_inner, SIGNAL(countryChosen(const QString&)), this, SIGNAL(countryChosen(const QString&)));
|
connect(_inner, SIGNAL(countryChosen(const QString&)), this, SIGNAL(countryChosen(const QString&)));
|
||||||
|
|
||||||
prepare();
|
raiseShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CountrySelectBox::onSubmit() {
|
void CountrySelectBox::onSubmit() {
|
||||||
|
|
|
@ -72,7 +72,7 @@ RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, QPoint origin,
|
||||||
}
|
}
|
||||||
_radiusTo = qRound(sqrt(_radiusTo));
|
_radiusTo = qRound(sqrt(_radiusTo));
|
||||||
|
|
||||||
_show.start(UpdateCallback(_update), 0., 1., _st.showDuration);
|
_show.start(UpdateCallback(_update), 0., 1., _st.showDuration, anim::easeOutCirc);
|
||||||
}
|
}
|
||||||
|
|
||||||
RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, const QPixmap &mask, const UpdateCallback &update)
|
RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, const QPixmap &mask, const UpdateCallback &update)
|
||||||
|
|
|
@ -26,320 +26,40 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "pspecific.h"
|
#include "pspecific.h"
|
||||||
|
|
||||||
|
namespace Images {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using LocalImages = QMap<QString, Image*>;
|
FORCE_INLINE uint64 blurGetColors(const uchar *p) {
|
||||||
LocalImages localImages;
|
return (uint64)p[0] + ((uint64)p[1] << 16) + ((uint64)p[2] << 32) + ((uint64)p[3] << 48);
|
||||||
|
|
||||||
using WebImages = QMap<QString, WebImage*>;
|
|
||||||
WebImages webImages;
|
|
||||||
|
|
||||||
Image *generateBlankImage() {
|
|
||||||
auto data = QImage(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
|
||||||
data.fill(Qt::transparent);
|
|
||||||
data.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
return internal::getImage(App::pixmapFromImageInPlace(std_::move(data)), "GIF");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Image *blank() {
|
const QPixmap &circleMask(int width, int height) {
|
||||||
static auto blankImage = generateBlankImage();
|
t_assert(Global::started());
|
||||||
return blankImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
using StorageImages = QMap<StorageKey, StorageImage*>;
|
uint64 key = uint64(uint32(width)) << 32 | uint64(uint32(height));
|
||||||
StorageImages storageImages;
|
|
||||||
|
|
||||||
int64 globalAcquiredSize = 0;
|
Global::CircleMasksMap &masks(Global::RefCircleMasks());
|
||||||
|
auto i = masks.constFind(key);
|
||||||
uint64 PixKey(int width, int height, ImagePixOptions options) {
|
if (i == masks.cend()) {
|
||||||
return static_cast<uint64>(width) | (static_cast<uint64>(height) << 24) | (static_cast<uint64>(options) << 48);
|
QImage mask(width, height, QImage::Format_ARGB32_Premultiplied);
|
||||||
}
|
{
|
||||||
|
Painter p(&mask);
|
||||||
uint64 SinglePixKey(ImagePixOptions options) {
|
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
return PixKey(0, 0, options);
|
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
p.fillRect(0, 0, width, height, Qt::transparent);
|
||||||
|
p.setBrush(Qt::white);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.drawEllipse(0, 0, width, height);
|
||||||
|
}
|
||||||
|
mask.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
i = masks.insert(key, App::pixmapFromImageInPlace(std_::move(mask)));
|
||||||
|
}
|
||||||
|
return i.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
StorageImageLocation StorageImageLocation::Null;
|
QImage prepareBlur(QImage img) {
|
||||||
|
|
||||||
bool Image::isNull() const {
|
|
||||||
return (this == blank());
|
|
||||||
}
|
|
||||||
|
|
||||||
ImagePtr::ImagePtr() : Parent(blank()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ImagePtr::ImagePtr(int32 width, int32 height, const MTPFileLocation &location, ImagePtr def) :
|
|
||||||
Parent((location.type() == mtpc_fileLocation) ? (Image*)(internal::getImage(StorageImageLocation(width, height, location.c_fileLocation()))) : def.v()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Image::Image(const QString &file, QByteArray fmt) : _forgot(false) {
|
|
||||||
_data = App::pixmapFromImageInPlace(App::readImage(file, &fmt, false, 0, &_saved));
|
|
||||||
_format = fmt;
|
|
||||||
if (!_data.isNull()) {
|
|
||||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image::Image(const QByteArray &filecontent, QByteArray fmt) : _forgot(false) {
|
|
||||||
_data = App::pixmapFromImageInPlace(App::readImage(filecontent, &fmt, false));
|
|
||||||
_format = fmt;
|
|
||||||
_saved = filecontent;
|
|
||||||
if (!_data.isNull()) {
|
|
||||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image::Image(const QPixmap &pixmap, QByteArray format) : _format(format), _forgot(false), _data(pixmap) {
|
|
||||||
if (!_data.isNull()) {
|
|
||||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image::Image(const QByteArray &filecontent, QByteArray fmt, const QPixmap &pixmap) : _saved(filecontent), _format(fmt), _forgot(false), _data(pixmap) {
|
|
||||||
_data = pixmap;
|
|
||||||
_format = fmt;
|
|
||||||
_saved = filecontent;
|
|
||||||
if (!_data.isNull()) {
|
|
||||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const QPixmap &Image::pix(int32 w, int32 h) const {
|
|
||||||
checkload();
|
|
||||||
|
|
||||||
if (w <= 0 || !width() || !height()) {
|
|
||||||
w = width();
|
|
||||||
} else if (cRetina()) {
|
|
||||||
w *= cIntRetinaFactor();
|
|
||||||
h *= cIntRetinaFactor();
|
|
||||||
}
|
|
||||||
auto options = ImagePixOption::Smooth | ImagePixOption::None;
|
|
||||||
auto k = PixKey(w, h, options);
|
|
||||||
auto i = _sizesCache.constFind(k);
|
|
||||||
if (i == _sizesCache.cend()) {
|
|
||||||
auto p = pixNoCache(w, h, options);
|
|
||||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
i = _sizesCache.insert(k, p);
|
|
||||||
if (!p.isNull()) {
|
|
||||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QPixmap &Image::pixRounded(int32 w, int32 h, ImageRoundRadius radius, ImageRoundCorners corners) const {
|
|
||||||
checkload();
|
|
||||||
|
|
||||||
if (w <= 0 || !width() || !height()) {
|
|
||||||
w = width();
|
|
||||||
} else if (cRetina()) {
|
|
||||||
w *= cIntRetinaFactor();
|
|
||||||
h *= cIntRetinaFactor();
|
|
||||||
}
|
|
||||||
auto options = ImagePixOption::Smooth | ImagePixOption::None;
|
|
||||||
auto cornerOptions = [](ImageRoundCorners corners) {
|
|
||||||
return (corners & ImageRoundCorner::TopLeft ? ImagePixOption::RoundedTopLeft : ImagePixOption::None)
|
|
||||||
| (corners & ImageRoundCorner::TopRight ? ImagePixOption::RoundedTopRight : ImagePixOption::None)
|
|
||||||
| (corners & ImageRoundCorner::BottomLeft ? ImagePixOption::RoundedBottomLeft : ImagePixOption::None)
|
|
||||||
| (corners & ImageRoundCorner::BottomRight ? ImagePixOption::RoundedBottomRight : ImagePixOption::None);
|
|
||||||
};
|
|
||||||
if (radius == ImageRoundRadius::Large) {
|
|
||||||
options |= ImagePixOption::RoundedLarge | cornerOptions(corners);
|
|
||||||
} else if (radius == ImageRoundRadius::Small) {
|
|
||||||
options |= ImagePixOption::RoundedSmall | cornerOptions(corners);
|
|
||||||
}
|
|
||||||
auto k = PixKey(w, h, options);
|
|
||||||
auto i = _sizesCache.constFind(k);
|
|
||||||
if (i == _sizesCache.cend()) {
|
|
||||||
auto p = pixNoCache(w, h, options);
|
|
||||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
i = _sizesCache.insert(k, p);
|
|
||||||
if (!p.isNull()) {
|
|
||||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QPixmap &Image::pixCircled(int32 w, int32 h) const {
|
|
||||||
checkload();
|
|
||||||
|
|
||||||
if (w <= 0 || !width() || !height()) {
|
|
||||||
w = width();
|
|
||||||
} else if (cRetina()) {
|
|
||||||
w *= cIntRetinaFactor();
|
|
||||||
h *= cIntRetinaFactor();
|
|
||||||
}
|
|
||||||
auto options = ImagePixOption::Smooth | ImagePixOption::Circled;
|
|
||||||
auto k = PixKey(w, h, options);
|
|
||||||
auto i = _sizesCache.constFind(k);
|
|
||||||
if (i == _sizesCache.cend()) {
|
|
||||||
auto p = pixNoCache(w, h, options);
|
|
||||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
i = _sizesCache.insert(k, p);
|
|
||||||
if (!p.isNull()) {
|
|
||||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QPixmap &Image::pixBlurred(int32 w, int32 h) const {
|
|
||||||
checkload();
|
|
||||||
|
|
||||||
if (w <= 0 || !width() || !height()) {
|
|
||||||
w = width() * cIntRetinaFactor();
|
|
||||||
} else if (cRetina()) {
|
|
||||||
w *= cIntRetinaFactor();
|
|
||||||
h *= cIntRetinaFactor();
|
|
||||||
}
|
|
||||||
auto options = ImagePixOption::Smooth | ImagePixOption::Blurred;
|
|
||||||
auto k = PixKey(w, h, options);
|
|
||||||
auto i = _sizesCache.constFind(k);
|
|
||||||
if (i == _sizesCache.cend()) {
|
|
||||||
auto p = pixNoCache(w, h, options);
|
|
||||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
i = _sizesCache.insert(k, p);
|
|
||||||
if (!p.isNull()) {
|
|
||||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QPixmap &Image::pixColored(const style::color &add, int32 w, int32 h) const {
|
|
||||||
checkload();
|
|
||||||
|
|
||||||
if (w <= 0 || !width() || !height()) {
|
|
||||||
w = width() * cIntRetinaFactor();
|
|
||||||
} else if (cRetina()) {
|
|
||||||
w *= cIntRetinaFactor();
|
|
||||||
h *= cIntRetinaFactor();
|
|
||||||
}
|
|
||||||
auto options = ImagePixOption::Smooth | ImagePixOption::Colored;
|
|
||||||
auto k = PixKey(w, h, options);
|
|
||||||
auto i = _sizesCache.constFind(k);
|
|
||||||
if (i == _sizesCache.cend()) {
|
|
||||||
auto p = pixColoredNoCache(add, w, h, true);
|
|
||||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
i = _sizesCache.insert(k, p);
|
|
||||||
if (!p.isNull()) {
|
|
||||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QPixmap &Image::pixBlurredColored(const style::color &add, int32 w, int32 h) const {
|
|
||||||
checkload();
|
|
||||||
|
|
||||||
if (w <= 0 || !width() || !height()) {
|
|
||||||
w = width() * cIntRetinaFactor();
|
|
||||||
} else if (cRetina()) {
|
|
||||||
w *= cIntRetinaFactor();
|
|
||||||
h *= cIntRetinaFactor();
|
|
||||||
}
|
|
||||||
auto options = ImagePixOption::Blurred | ImagePixOption::Smooth | ImagePixOption::Colored;
|
|
||||||
auto k = PixKey(w, h, options);
|
|
||||||
auto i = _sizesCache.constFind(k);
|
|
||||||
if (i == _sizesCache.cend()) {
|
|
||||||
auto p = pixBlurredColoredNoCache(add, w, h);
|
|
||||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
i = _sizesCache.insert(k, p);
|
|
||||||
if (!p.isNull()) {
|
|
||||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QPixmap &Image::pixSingle(int32 w, int32 h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners) const {
|
|
||||||
checkload();
|
|
||||||
|
|
||||||
if (w <= 0 || !width() || !height()) {
|
|
||||||
w = width() * cIntRetinaFactor();
|
|
||||||
} else if (cRetina()) {
|
|
||||||
w *= cIntRetinaFactor();
|
|
||||||
h *= cIntRetinaFactor();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto options = ImagePixOption::Smooth | ImagePixOption::None;
|
|
||||||
auto cornerOptions = [](ImageRoundCorners corners) {
|
|
||||||
return (corners & ImageRoundCorner::TopLeft ? ImagePixOption::RoundedTopLeft : ImagePixOption::None)
|
|
||||||
| (corners & ImageRoundCorner::TopRight ? ImagePixOption::RoundedTopRight : ImagePixOption::None)
|
|
||||||
| (corners & ImageRoundCorner::BottomLeft ? ImagePixOption::RoundedBottomLeft : ImagePixOption::None)
|
|
||||||
| (corners & ImageRoundCorner::BottomRight ? ImagePixOption::RoundedBottomRight : ImagePixOption::None);
|
|
||||||
};
|
|
||||||
if (radius == ImageRoundRadius::Large) {
|
|
||||||
options |= ImagePixOption::RoundedLarge | cornerOptions(corners);
|
|
||||||
} else if (radius == ImageRoundRadius::Small) {
|
|
||||||
options |= ImagePixOption::RoundedSmall | cornerOptions(corners);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto k = SinglePixKey(options);
|
|
||||||
auto i = _sizesCache.constFind(k);
|
|
||||||
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
|
|
||||||
if (i != _sizesCache.cend()) {
|
|
||||||
globalAcquiredSize -= int64(i->width()) * i->height() * 4;
|
|
||||||
}
|
|
||||||
auto p = pixNoCache(w, h, options, outerw, outerh);
|
|
||||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
i = _sizesCache.insert(k, p);
|
|
||||||
if (!p.isNull()) {
|
|
||||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QPixmap &Image::pixBlurredSingle(int w, int h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners) const {
|
|
||||||
checkload();
|
|
||||||
|
|
||||||
if (w <= 0 || !width() || !height()) {
|
|
||||||
w = width() * cIntRetinaFactor();
|
|
||||||
} else if (cRetina()) {
|
|
||||||
w *= cIntRetinaFactor();
|
|
||||||
h *= cIntRetinaFactor();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto options = ImagePixOption::Smooth | ImagePixOption::Blurred;
|
|
||||||
auto cornerOptions = [](ImageRoundCorners corners) {
|
|
||||||
return (corners & ImageRoundCorner::TopLeft ? ImagePixOption::RoundedTopLeft : ImagePixOption::None)
|
|
||||||
| (corners & ImageRoundCorner::TopRight ? ImagePixOption::RoundedTopRight : ImagePixOption::None)
|
|
||||||
| (corners & ImageRoundCorner::BottomLeft ? ImagePixOption::RoundedBottomLeft : ImagePixOption::None)
|
|
||||||
| (corners & ImageRoundCorner::BottomRight ? ImagePixOption::RoundedBottomRight : ImagePixOption::None);
|
|
||||||
};
|
|
||||||
if (radius == ImageRoundRadius::Large) {
|
|
||||||
options |= ImagePixOption::RoundedLarge | cornerOptions(corners);
|
|
||||||
} else if (radius == ImageRoundRadius::Small) {
|
|
||||||
options |= ImagePixOption::RoundedSmall | cornerOptions(corners);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto k = SinglePixKey(options);
|
|
||||||
auto i = _sizesCache.constFind(k);
|
|
||||||
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
|
|
||||||
if (i != _sizesCache.cend()) {
|
|
||||||
globalAcquiredSize -= int64(i->width()) * i->height() * 4;
|
|
||||||
}
|
|
||||||
auto p = pixNoCache(w, h, options, outerw, outerh);
|
|
||||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
i = _sizesCache.insert(k, p);
|
|
||||||
if (!p.isNull()) {
|
|
||||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
static inline uint64 _blurGetColors(const uchar *p) {
|
|
||||||
return (uint64)p[0] + ((uint64)p[1] << 16) + ((uint64)p[2] << 32) + ((uint64)p[3] << 48);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage imageBlur(QImage img) {
|
|
||||||
QImage::Format fmt = img.format();
|
QImage::Format fmt = img.format();
|
||||||
if (fmt != QImage::Format_RGB32 && fmt != QImage::Format_ARGB32_Premultiplied) {
|
if (fmt != QImage::Format_RGB32 && fmt != QImage::Format_ARGB32_Premultiplied) {
|
||||||
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||||
|
@ -379,12 +99,12 @@ QImage imageBlur(QImage img) {
|
||||||
int yw = 0;
|
int yw = 0;
|
||||||
const int we = w - r1;
|
const int we = w - r1;
|
||||||
for (y = 0; y < h; y++) {
|
for (y = 0; y < h; y++) {
|
||||||
uint64 cur = _blurGetColors(&pix[yw]);
|
uint64 cur = blurGetColors(&pix[yw]);
|
||||||
uint64 rgballsum = -radius * cur;
|
uint64 rgballsum = -radius * cur;
|
||||||
uint64 rgbsum = cur * ((r1 * (r1 + 1)) >> 1);
|
uint64 rgbsum = cur * ((r1 * (r1 + 1)) >> 1);
|
||||||
|
|
||||||
for (i = 1; i <= radius; i++) {
|
for (i = 1; i <= radius; i++) {
|
||||||
uint64 cur = _blurGetColors(&pix[yw + i * 4]);
|
uint64 cur = blurGetColors(&pix[yw + i * 4]);
|
||||||
rgbsum += cur * (r1 - i);
|
rgbsum += cur * (r1 - i);
|
||||||
rgballsum += cur;
|
rgballsum += cur;
|
||||||
}
|
}
|
||||||
|
@ -393,7 +113,7 @@ QImage imageBlur(QImage img) {
|
||||||
|
|
||||||
#define update(start, middle, end) \
|
#define update(start, middle, end) \
|
||||||
rgb[y * w + x] = (rgbsum >> 4) & 0x00FF00FF00FF00FFLL; \
|
rgb[y * w + x] = (rgbsum >> 4) & 0x00FF00FF00FF00FFLL; \
|
||||||
rgballsum += _blurGetColors(&pix[yw + (start) * 4]) - 2 * _blurGetColors(&pix[yw + (middle) * 4]) + _blurGetColors(&pix[yw + (end) * 4]); \
|
rgballsum += blurGetColors(&pix[yw + (start) * 4]) - 2 * blurGetColors(&pix[yw + (middle) * 4]) + blurGetColors(&pix[yw + (end) * 4]); \
|
||||||
rgbsum += rgballsum; \
|
rgbsum += rgballsum; \
|
||||||
x++;
|
x++;
|
||||||
|
|
||||||
|
@ -454,31 +174,7 @@ yi += stride;
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QPixmap &circleMask(int width, int height) {
|
void prepareCircle(QImage &img) {
|
||||||
t_assert(Global::started());
|
|
||||||
|
|
||||||
uint64 key = uint64(uint32(width)) << 32 | uint64(uint32(height));
|
|
||||||
|
|
||||||
Global::CircleMasksMap &masks(Global::RefCircleMasks());
|
|
||||||
auto i = masks.constFind(key);
|
|
||||||
if (i == masks.cend()) {
|
|
||||||
QImage mask(width, height, QImage::Format_ARGB32_Premultiplied);
|
|
||||||
{
|
|
||||||
Painter p(&mask);
|
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
|
||||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
|
||||||
p.fillRect(0, 0, width, height, Qt::transparent);
|
|
||||||
p.setBrush(Qt::white);
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.drawEllipse(0, 0, width, height);
|
|
||||||
}
|
|
||||||
mask.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
i = masks.insert(key, App::pixmapFromImageInPlace(std_::move(mask)));
|
|
||||||
}
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
void imageCircle(QImage &img) {
|
|
||||||
t_assert(!img.isNull());
|
t_assert(!img.isNull());
|
||||||
|
|
||||||
img.setDevicePixelRatio(cRetinaFactor());
|
img.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
@ -491,7 +187,7 @@ void imageCircle(QImage &img) {
|
||||||
p.drawPixmap(0, 0, mask);
|
p.drawPixmap(0, 0, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void imageRound(QImage &image, ImageRoundRadius radius, ImageRoundCorners corners) {
|
void prepareRound(QImage &image, ImageRoundRadius radius, ImageRoundCorners corners) {
|
||||||
if (!static_cast<int>(corners)) {
|
if (!static_cast<int>(corners)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -508,7 +204,7 @@ void imageRound(QImage &image, ImageRoundRadius radius, ImageRoundCorners corner
|
||||||
auto imageHeight = image.height();
|
auto imageHeight = image.height();
|
||||||
if (imageWidth < 2 * cornerWidth || imageHeight < 2 * cornerHeight) {
|
if (imageWidth < 2 * cornerWidth || imageHeight < 2 * cornerHeight) {
|
||||||
if (radius == ImageRoundRadius::Large) {
|
if (radius == ImageRoundRadius::Large) {
|
||||||
return imageRound(image, ImageRoundRadius::Small, corners);
|
return prepareRound(image, ImageRoundRadius::Small, corners);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -550,16 +246,15 @@ void imageRound(QImage &image, ImageRoundRadius radius, ImageRoundCorners corner
|
||||||
if (corners & ImageRoundCorner::BottomRight) maskCorner(intsBottomRight, masks[3]);
|
if (corners & ImageRoundCorner::BottomRight) maskCorner(intsBottomRight, masks[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage imageColored(const style::color &add, QImage img) {
|
QImage prepareColored(const style::color &add, QImage image) {
|
||||||
QImage::Format fmt = img.format();
|
auto format = image.format();
|
||||||
if (fmt != QImage::Format_RGB32 && fmt != QImage::Format_ARGB32_Premultiplied) {
|
if (format != QImage::Format_RGB32 && format != QImage::Format_ARGB32_Premultiplied) {
|
||||||
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
image = std_::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||||
}
|
}
|
||||||
|
|
||||||
uchar *pix = img.bits();
|
if (auto pix = image.bits()) {
|
||||||
if (pix) {
|
|
||||||
int ca = int(add->c.alphaF() * 0xFF), cr = int(add->c.redF() * 0xFF), cg = int(add->c.greenF() * 0xFF), cb = int(add->c.blueF() * 0xFF);
|
int ca = int(add->c.alphaF() * 0xFF), cr = int(add->c.redF() * 0xFF), cg = int(add->c.greenF() * 0xFF), cb = int(add->c.blueF() * 0xFF);
|
||||||
const int w = img.width(), h = img.height(), size = w * h * 4;
|
const int w = image.width(), h = image.height(), size = w * h * 4;
|
||||||
for (int32 i = 0; i < size; i += 4) {
|
for (int32 i = 0; i < size; i += 4) {
|
||||||
int b = pix[i], g = pix[i + 1], r = pix[i + 2], a = pix[i + 3], aca = a * ca;
|
int b = pix[i], g = pix[i + 1], r = pix[i + 2], a = pix[i + 3], aca = a * ca;
|
||||||
pix[i + 0] = uchar(b + ((aca * (cb - b)) >> 16));
|
pix[i + 0] = uchar(b + ((aca * (cb - b)) >> 16));
|
||||||
|
@ -568,21 +263,39 @@ QImage imageColored(const style::color &add, QImage img) {
|
||||||
pix[i + 3] = uchar(a + ((aca * (0xFF - a)) >> 16));
|
pix[i + 3] = uchar(a + ((aca * (0xFF - a)) >> 16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return img;
|
return std_::move(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap imagePix(QImage img, int32 w, int32 h, ImagePixOptions options, int32 outerw, int32 outerh) {
|
QImage prepareOpaque(QImage image) {
|
||||||
|
if (image.hasAlphaChannel()) {
|
||||||
|
image = std_::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||||
|
auto ints = reinterpret_cast<uint32*>(image.bits());
|
||||||
|
auto bg = anim::shifted(st::imageBgTransparent->c);
|
||||||
|
auto width = image.width();
|
||||||
|
auto height = image.height();
|
||||||
|
auto addPerLine = (image.bytesPerLine() / sizeof(uint32)) - width;
|
||||||
|
for (auto y = 0; y != height; ++y) {
|
||||||
|
for (auto x = 0; x != width; ++x) {
|
||||||
|
auto components = anim::shifted(*ints);
|
||||||
|
*ints = anim::unshifted(components * 256 + bg * (256 - anim::getAlpha(components)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std_::move(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage prepare(QImage img, int w, int h, Images::Options options, int outerw, int outerh) {
|
||||||
t_assert(!img.isNull());
|
t_assert(!img.isNull());
|
||||||
if (options.testFlag(ImagePixOption::Blurred)) {
|
if (options.testFlag(Images::Option::Blurred)) {
|
||||||
img = imageBlur(img);
|
img = prepareBlur(img);
|
||||||
t_assert(!img.isNull());
|
t_assert(!img.isNull());
|
||||||
}
|
}
|
||||||
if (w <= 0 || (w == img.width() && (h <= 0 || h == img.height()))) {
|
if (w <= 0 || (w == img.width() && (h <= 0 || h == img.height()))) {
|
||||||
} else if (h <= 0) {
|
} else if (h <= 0) {
|
||||||
img = img.scaledToWidth(w, options.testFlag(ImagePixOption::Smooth) ? Qt::SmoothTransformation : Qt::FastTransformation);
|
img = img.scaledToWidth(w, options.testFlag(Images::Option::Smooth) ? Qt::SmoothTransformation : Qt::FastTransformation);
|
||||||
t_assert(!img.isNull());
|
t_assert(!img.isNull());
|
||||||
} else {
|
} else {
|
||||||
img = img.scaled(w, h, Qt::IgnoreAspectRatio, options.testFlag(ImagePixOption::Smooth) ? Qt::SmoothTransformation : Qt::FastTransformation);
|
img = img.scaled(w, h, Qt::IgnoreAspectRatio, options.testFlag(Images::Option::Smooth) ? Qt::SmoothTransformation : Qt::FastTransformation);
|
||||||
t_assert(!img.isNull());
|
t_assert(!img.isNull());
|
||||||
}
|
}
|
||||||
if (outerw > 0 && outerh > 0) {
|
if (outerw > 0 && outerh > 0) {
|
||||||
|
@ -603,26 +316,336 @@ QPixmap imagePix(QImage img, int32 w, int32 h, ImagePixOptions options, int32 ou
|
||||||
t_assert(!img.isNull());
|
t_assert(!img.isNull());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto corners = [](ImagePixOptions options) {
|
auto corners = [](Images::Options options) {
|
||||||
return (options.testFlag(ImagePixOption::RoundedTopLeft) ? ImageRoundCorner::TopLeft : ImageRoundCorner::None)
|
return (options.testFlag(Images::Option::RoundedTopLeft) ? ImageRoundCorner::TopLeft : ImageRoundCorner::None)
|
||||||
| (options.testFlag(ImagePixOption::RoundedTopRight) ? ImageRoundCorner::TopRight : ImageRoundCorner::None)
|
| (options.testFlag(Images::Option::RoundedTopRight) ? ImageRoundCorner::TopRight : ImageRoundCorner::None)
|
||||||
| (options.testFlag(ImagePixOption::RoundedBottomLeft) ? ImageRoundCorner::BottomLeft : ImageRoundCorner::None)
|
| (options.testFlag(Images::Option::RoundedBottomLeft) ? ImageRoundCorner::BottomLeft : ImageRoundCorner::None)
|
||||||
| (options.testFlag(ImagePixOption::RoundedBottomRight) ? ImageRoundCorner::BottomRight : ImageRoundCorner::None);
|
| (options.testFlag(Images::Option::RoundedBottomRight) ? ImageRoundCorner::BottomRight : ImageRoundCorner::None);
|
||||||
};
|
};
|
||||||
if (options.testFlag(ImagePixOption::Circled)) {
|
if (options.testFlag(Images::Option::Circled)) {
|
||||||
imageCircle(img);
|
prepareCircle(img);
|
||||||
t_assert(!img.isNull());
|
t_assert(!img.isNull());
|
||||||
} else if (options.testFlag(ImagePixOption::RoundedLarge)) {
|
} else if (options.testFlag(Images::Option::RoundedLarge)) {
|
||||||
imageRound(img, ImageRoundRadius::Large, corners(options));
|
prepareRound(img, ImageRoundRadius::Large, corners(options));
|
||||||
|
t_assert(!img.isNull());
|
||||||
|
} else if (options.testFlag(Images::Option::RoundedSmall)) {
|
||||||
|
prepareRound(img, ImageRoundRadius::Small, corners(options));
|
||||||
t_assert(!img.isNull());
|
t_assert(!img.isNull());
|
||||||
} else if (options.testFlag(ImagePixOption::RoundedSmall)) {
|
|
||||||
imageRound(img, ImageRoundRadius::Small, corners(options));
|
|
||||||
}
|
}
|
||||||
img.setDevicePixelRatio(cRetinaFactor());
|
img.setDevicePixelRatio(cRetinaFactor());
|
||||||
return App::pixmapFromImageInPlace(std_::move(img));
|
return std_::move(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap Image::pixNoCache(int w, int h, ImagePixOptions options, int outerw, int outerh) const {
|
} // namespace Images
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using LocalImages = QMap<QString, Image*>;
|
||||||
|
LocalImages localImages;
|
||||||
|
|
||||||
|
using WebImages = QMap<QString, WebImage*>;
|
||||||
|
WebImages webImages;
|
||||||
|
|
||||||
|
Image *generateBlankImage() {
|
||||||
|
auto data = QImage(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||||
|
data.fill(Qt::transparent);
|
||||||
|
data.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
return internal::getImage(App::pixmapFromImageInPlace(std_::move(data)), "GIF");
|
||||||
|
}
|
||||||
|
|
||||||
|
Image *blank() {
|
||||||
|
static auto blankImage = generateBlankImage();
|
||||||
|
return blankImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
using StorageImages = QMap<StorageKey, StorageImage*>;
|
||||||
|
StorageImages storageImages;
|
||||||
|
|
||||||
|
int64 globalAcquiredSize = 0;
|
||||||
|
|
||||||
|
uint64 PixKey(int width, int height, Images::Options options) {
|
||||||
|
return static_cast<uint64>(width) | (static_cast<uint64>(height) << 24) | (static_cast<uint64>(options) << 48);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 SinglePixKey(Images::Options options) {
|
||||||
|
return PixKey(0, 0, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
StorageImageLocation StorageImageLocation::Null;
|
||||||
|
|
||||||
|
bool Image::isNull() const {
|
||||||
|
return (this == blank());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImagePtr::ImagePtr() : Parent(blank()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ImagePtr::ImagePtr(int32 width, int32 height, const MTPFileLocation &location, ImagePtr def) :
|
||||||
|
Parent((location.type() == mtpc_fileLocation) ? (Image*)(internal::getImage(StorageImageLocation(width, height, location.c_fileLocation()))) : def.v()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::Image(const QString &file, QByteArray fmt) : _forgot(false) {
|
||||||
|
_data = App::pixmapFromImageInPlace(App::readImage(file, &fmt, false, 0, &_saved));
|
||||||
|
_format = fmt;
|
||||||
|
if (!_data.isNull()) {
|
||||||
|
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::Image(const QByteArray &filecontent, QByteArray fmt) : _forgot(false) {
|
||||||
|
_data = App::pixmapFromImageInPlace(App::readImage(filecontent, &fmt, false));
|
||||||
|
_format = fmt;
|
||||||
|
_saved = filecontent;
|
||||||
|
if (!_data.isNull()) {
|
||||||
|
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::Image(const QPixmap &pixmap, QByteArray format) : _format(format), _forgot(false), _data(pixmap) {
|
||||||
|
if (!_data.isNull()) {
|
||||||
|
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::Image(const QByteArray &filecontent, QByteArray fmt, const QPixmap &pixmap) : _saved(filecontent), _format(fmt), _forgot(false), _data(pixmap) {
|
||||||
|
_data = pixmap;
|
||||||
|
_format = fmt;
|
||||||
|
_saved = filecontent;
|
||||||
|
if (!_data.isNull()) {
|
||||||
|
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap &Image::pix(int32 w, int32 h) const {
|
||||||
|
checkload();
|
||||||
|
|
||||||
|
if (w <= 0 || !width() || !height()) {
|
||||||
|
w = width();
|
||||||
|
} else if (cRetina()) {
|
||||||
|
w *= cIntRetinaFactor();
|
||||||
|
h *= cIntRetinaFactor();
|
||||||
|
}
|
||||||
|
auto options = Images::Option::Smooth | Images::Option::None;
|
||||||
|
auto k = PixKey(w, h, options);
|
||||||
|
auto i = _sizesCache.constFind(k);
|
||||||
|
if (i == _sizesCache.cend()) {
|
||||||
|
auto p = pixNoCache(w, h, options);
|
||||||
|
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
i = _sizesCache.insert(k, p);
|
||||||
|
if (!p.isNull()) {
|
||||||
|
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap &Image::pixRounded(int32 w, int32 h, ImageRoundRadius radius, ImageRoundCorners corners) const {
|
||||||
|
checkload();
|
||||||
|
|
||||||
|
if (w <= 0 || !width() || !height()) {
|
||||||
|
w = width();
|
||||||
|
} else if (cRetina()) {
|
||||||
|
w *= cIntRetinaFactor();
|
||||||
|
h *= cIntRetinaFactor();
|
||||||
|
}
|
||||||
|
auto options = Images::Option::Smooth | Images::Option::None;
|
||||||
|
auto cornerOptions = [](ImageRoundCorners corners) {
|
||||||
|
return (corners & ImageRoundCorner::TopLeft ? Images::Option::RoundedTopLeft : Images::Option::None)
|
||||||
|
| (corners & ImageRoundCorner::TopRight ? Images::Option::RoundedTopRight : Images::Option::None)
|
||||||
|
| (corners & ImageRoundCorner::BottomLeft ? Images::Option::RoundedBottomLeft : Images::Option::None)
|
||||||
|
| (corners & ImageRoundCorner::BottomRight ? Images::Option::RoundedBottomRight : Images::Option::None);
|
||||||
|
};
|
||||||
|
if (radius == ImageRoundRadius::Large) {
|
||||||
|
options |= Images::Option::RoundedLarge | cornerOptions(corners);
|
||||||
|
} else if (radius == ImageRoundRadius::Small) {
|
||||||
|
options |= Images::Option::RoundedSmall | cornerOptions(corners);
|
||||||
|
}
|
||||||
|
auto k = PixKey(w, h, options);
|
||||||
|
auto i = _sizesCache.constFind(k);
|
||||||
|
if (i == _sizesCache.cend()) {
|
||||||
|
auto p = pixNoCache(w, h, options);
|
||||||
|
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
i = _sizesCache.insert(k, p);
|
||||||
|
if (!p.isNull()) {
|
||||||
|
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap &Image::pixCircled(int32 w, int32 h) const {
|
||||||
|
checkload();
|
||||||
|
|
||||||
|
if (w <= 0 || !width() || !height()) {
|
||||||
|
w = width();
|
||||||
|
} else if (cRetina()) {
|
||||||
|
w *= cIntRetinaFactor();
|
||||||
|
h *= cIntRetinaFactor();
|
||||||
|
}
|
||||||
|
auto options = Images::Option::Smooth | Images::Option::Circled;
|
||||||
|
auto k = PixKey(w, h, options);
|
||||||
|
auto i = _sizesCache.constFind(k);
|
||||||
|
if (i == _sizesCache.cend()) {
|
||||||
|
auto p = pixNoCache(w, h, options);
|
||||||
|
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
i = _sizesCache.insert(k, p);
|
||||||
|
if (!p.isNull()) {
|
||||||
|
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap &Image::pixBlurred(int32 w, int32 h) const {
|
||||||
|
checkload();
|
||||||
|
|
||||||
|
if (w <= 0 || !width() || !height()) {
|
||||||
|
w = width() * cIntRetinaFactor();
|
||||||
|
} else if (cRetina()) {
|
||||||
|
w *= cIntRetinaFactor();
|
||||||
|
h *= cIntRetinaFactor();
|
||||||
|
}
|
||||||
|
auto options = Images::Option::Smooth | Images::Option::Blurred;
|
||||||
|
auto k = PixKey(w, h, options);
|
||||||
|
auto i = _sizesCache.constFind(k);
|
||||||
|
if (i == _sizesCache.cend()) {
|
||||||
|
auto p = pixNoCache(w, h, options);
|
||||||
|
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
i = _sizesCache.insert(k, p);
|
||||||
|
if (!p.isNull()) {
|
||||||
|
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap &Image::pixColored(const style::color &add, int32 w, int32 h) const {
|
||||||
|
checkload();
|
||||||
|
|
||||||
|
if (w <= 0 || !width() || !height()) {
|
||||||
|
w = width() * cIntRetinaFactor();
|
||||||
|
} else if (cRetina()) {
|
||||||
|
w *= cIntRetinaFactor();
|
||||||
|
h *= cIntRetinaFactor();
|
||||||
|
}
|
||||||
|
auto options = Images::Option::Smooth | Images::Option::Colored;
|
||||||
|
auto k = PixKey(w, h, options);
|
||||||
|
auto i = _sizesCache.constFind(k);
|
||||||
|
if (i == _sizesCache.cend()) {
|
||||||
|
auto p = pixColoredNoCache(add, w, h, true);
|
||||||
|
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
i = _sizesCache.insert(k, p);
|
||||||
|
if (!p.isNull()) {
|
||||||
|
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap &Image::pixBlurredColored(const style::color &add, int32 w, int32 h) const {
|
||||||
|
checkload();
|
||||||
|
|
||||||
|
if (w <= 0 || !width() || !height()) {
|
||||||
|
w = width() * cIntRetinaFactor();
|
||||||
|
} else if (cRetina()) {
|
||||||
|
w *= cIntRetinaFactor();
|
||||||
|
h *= cIntRetinaFactor();
|
||||||
|
}
|
||||||
|
auto options = Images::Option::Blurred | Images::Option::Smooth | Images::Option::Colored;
|
||||||
|
auto k = PixKey(w, h, options);
|
||||||
|
auto i = _sizesCache.constFind(k);
|
||||||
|
if (i == _sizesCache.cend()) {
|
||||||
|
auto p = pixBlurredColoredNoCache(add, w, h);
|
||||||
|
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
i = _sizesCache.insert(k, p);
|
||||||
|
if (!p.isNull()) {
|
||||||
|
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap &Image::pixSingle(int32 w, int32 h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners) const {
|
||||||
|
checkload();
|
||||||
|
|
||||||
|
if (w <= 0 || !width() || !height()) {
|
||||||
|
w = width() * cIntRetinaFactor();
|
||||||
|
} else if (cRetina()) {
|
||||||
|
w *= cIntRetinaFactor();
|
||||||
|
h *= cIntRetinaFactor();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto options = Images::Option::Smooth | Images::Option::None;
|
||||||
|
auto cornerOptions = [](ImageRoundCorners corners) {
|
||||||
|
return (corners & ImageRoundCorner::TopLeft ? Images::Option::RoundedTopLeft : Images::Option::None)
|
||||||
|
| (corners & ImageRoundCorner::TopRight ? Images::Option::RoundedTopRight : Images::Option::None)
|
||||||
|
| (corners & ImageRoundCorner::BottomLeft ? Images::Option::RoundedBottomLeft : Images::Option::None)
|
||||||
|
| (corners & ImageRoundCorner::BottomRight ? Images::Option::RoundedBottomRight : Images::Option::None);
|
||||||
|
};
|
||||||
|
if (radius == ImageRoundRadius::Large) {
|
||||||
|
options |= Images::Option::RoundedLarge | cornerOptions(corners);
|
||||||
|
} else if (radius == ImageRoundRadius::Small) {
|
||||||
|
options |= Images::Option::RoundedSmall | cornerOptions(corners);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto k = SinglePixKey(options);
|
||||||
|
auto i = _sizesCache.constFind(k);
|
||||||
|
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
|
||||||
|
if (i != _sizesCache.cend()) {
|
||||||
|
globalAcquiredSize -= int64(i->width()) * i->height() * 4;
|
||||||
|
}
|
||||||
|
auto p = pixNoCache(w, h, options, outerw, outerh);
|
||||||
|
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
i = _sizesCache.insert(k, p);
|
||||||
|
if (!p.isNull()) {
|
||||||
|
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap &Image::pixBlurredSingle(int w, int h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners) const {
|
||||||
|
checkload();
|
||||||
|
|
||||||
|
if (w <= 0 || !width() || !height()) {
|
||||||
|
w = width() * cIntRetinaFactor();
|
||||||
|
} else if (cRetina()) {
|
||||||
|
w *= cIntRetinaFactor();
|
||||||
|
h *= cIntRetinaFactor();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto options = Images::Option::Smooth | Images::Option::Blurred;
|
||||||
|
auto cornerOptions = [](ImageRoundCorners corners) {
|
||||||
|
return (corners & ImageRoundCorner::TopLeft ? Images::Option::RoundedTopLeft : Images::Option::None)
|
||||||
|
| (corners & ImageRoundCorner::TopRight ? Images::Option::RoundedTopRight : Images::Option::None)
|
||||||
|
| (corners & ImageRoundCorner::BottomLeft ? Images::Option::RoundedBottomLeft : Images::Option::None)
|
||||||
|
| (corners & ImageRoundCorner::BottomRight ? Images::Option::RoundedBottomRight : Images::Option::None);
|
||||||
|
};
|
||||||
|
if (radius == ImageRoundRadius::Large) {
|
||||||
|
options |= Images::Option::RoundedLarge | cornerOptions(corners);
|
||||||
|
} else if (radius == ImageRoundRadius::Small) {
|
||||||
|
options |= Images::Option::RoundedSmall | cornerOptions(corners);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto k = SinglePixKey(options);
|
||||||
|
auto i = _sizesCache.constFind(k);
|
||||||
|
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
|
||||||
|
if (i != _sizesCache.cend()) {
|
||||||
|
globalAcquiredSize -= int64(i->width()) * i->height() * 4;
|
||||||
|
}
|
||||||
|
auto p = pixNoCache(w, h, options, outerw, outerh);
|
||||||
|
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
i = _sizesCache.insert(k, p);
|
||||||
|
if (!p.isNull()) {
|
||||||
|
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap Image::pixNoCache(int w, int h, Images::Options options, int outerw, int outerh) const {
|
||||||
if (!loading()) const_cast<Image*>(this)->load();
|
if (!loading()) const_cast<Image*>(this)->load();
|
||||||
restore();
|
restore();
|
||||||
|
|
||||||
|
@ -653,23 +676,23 @@ QPixmap Image::pixNoCache(int w, int h, ImagePixOptions options, int outerw, int
|
||||||
p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), st::imageBgTransparent);
|
p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), st::imageBgTransparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto corners = [](ImagePixOptions options) {
|
auto corners = [](Images::Options options) {
|
||||||
return (options.testFlag(ImagePixOption::RoundedTopLeft) ? ImageRoundCorner::TopLeft : ImageRoundCorner::None)
|
return (options.testFlag(Images::Option::RoundedTopLeft) ? ImageRoundCorner::TopLeft : ImageRoundCorner::None)
|
||||||
| (options.testFlag(ImagePixOption::RoundedTopRight) ? ImageRoundCorner::TopRight : ImageRoundCorner::None)
|
| (options.testFlag(Images::Option::RoundedTopRight) ? ImageRoundCorner::TopRight : ImageRoundCorner::None)
|
||||||
| (options.testFlag(ImagePixOption::RoundedBottomLeft) ? ImageRoundCorner::BottomLeft : ImageRoundCorner::None)
|
| (options.testFlag(Images::Option::RoundedBottomLeft) ? ImageRoundCorner::BottomLeft : ImageRoundCorner::None)
|
||||||
| (options.testFlag(ImagePixOption::RoundedBottomRight) ? ImageRoundCorner::BottomRight : ImageRoundCorner::None);
|
| (options.testFlag(Images::Option::RoundedBottomRight) ? ImageRoundCorner::BottomRight : ImageRoundCorner::None);
|
||||||
};
|
};
|
||||||
if (options.testFlag(ImagePixOption::Circled)) {
|
if (options.testFlag(Images::Option::Circled)) {
|
||||||
imageCircle(result);
|
Images::prepareCircle(result);
|
||||||
} else if (options.testFlag(ImagePixOption::RoundedLarge)) {
|
} else if (options.testFlag(Images::Option::RoundedLarge)) {
|
||||||
imageRound(result, ImageRoundRadius::Large, corners(options));
|
Images::prepareRound(result, ImageRoundRadius::Large, corners(options));
|
||||||
} else if (options.testFlag(ImagePixOption::RoundedSmall)) {
|
} else if (options.testFlag(Images::Option::RoundedSmall)) {
|
||||||
imageRound(result, ImageRoundRadius::Small, corners(options));
|
Images::prepareRound(result, ImageRoundRadius::Small, corners(options));
|
||||||
}
|
}
|
||||||
return App::pixmapFromImageInPlace(std_::move(result));
|
return App::pixmapFromImageInPlace(std_::move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
return imagePix(_data.toImage(), w, h, options, outerw, outerh);
|
return Images::pixmap(_data.toImage(), w, h, options, outerw, outerh);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap Image::pixColoredNoCache(const style::color &add, int32 w, int32 h, bool smooth) const {
|
QPixmap Image::pixColoredNoCache(const style::color &add, int32 w, int32 h, bool smooth) const {
|
||||||
|
@ -678,11 +701,11 @@ QPixmap Image::pixColoredNoCache(const style::color &add, int32 w, int32 h, bool
|
||||||
if (_data.isNull()) return blank()->pix();
|
if (_data.isNull()) return blank()->pix();
|
||||||
|
|
||||||
QImage img = _data.toImage();
|
QImage img = _data.toImage();
|
||||||
if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) return App::pixmapFromImageInPlace(imageColored(add, img));
|
if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) return App::pixmapFromImageInPlace(Images::prepareColored(add, img));
|
||||||
if (h <= 0) {
|
if (h <= 0) {
|
||||||
return App::pixmapFromImageInPlace(imageColored(add, img.scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)));
|
return App::pixmapFromImageInPlace(Images::prepareColored(add, img.scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)));
|
||||||
}
|
}
|
||||||
return App::pixmapFromImageInPlace(imageColored(add, img.scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)));
|
return App::pixmapFromImageInPlace(Images::prepareColored(add, img.scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)));
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap Image::pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h) const {
|
QPixmap Image::pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h) const {
|
||||||
|
@ -690,14 +713,14 @@ QPixmap Image::pixBlurredColoredNoCache(const style::color &add, int32 w, int32
|
||||||
restore();
|
restore();
|
||||||
if (_data.isNull()) return blank()->pix();
|
if (_data.isNull()) return blank()->pix();
|
||||||
|
|
||||||
QImage img = imageBlur(_data.toImage());
|
QImage img = Images::prepareBlur(_data.toImage());
|
||||||
if (h <= 0) {
|
if (h <= 0) {
|
||||||
img = img.scaledToWidth(w, Qt::SmoothTransformation);
|
img = img.scaledToWidth(w, Qt::SmoothTransformation);
|
||||||
} else {
|
} else {
|
||||||
img = img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
img = img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return App::pixmapFromImageInPlace(imageColored(add, img));
|
return App::pixmapFromImageInPlace(Images::prepareColored(add, img));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::forget() const {
|
void Image::forget() const {
|
||||||
|
|
|
@ -38,10 +38,6 @@ enum class ImageRoundCorner {
|
||||||
Q_DECLARE_FLAGS(ImageRoundCorners, ImageRoundCorner);
|
Q_DECLARE_FLAGS(ImageRoundCorners, ImageRoundCorner);
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(ImageRoundCorners);
|
Q_DECLARE_OPERATORS_FOR_FLAGS(ImageRoundCorners);
|
||||||
|
|
||||||
QImage imageBlur(QImage image);
|
|
||||||
void imageRound(QImage &image, ImageRoundRadius radius, ImageRoundCorners corners = ImageRoundCorner::All);
|
|
||||||
void imageCircle(QImage &image);
|
|
||||||
|
|
||||||
inline uint32 packInt(int32 a) {
|
inline uint32 packInt(int32 a) {
|
||||||
return (a < 0) ? uint32(int64(a) + 0x100000000LL) : uint32(a);
|
return (a < 0) ? uint32(int64(a) + 0x100000000LL) : uint32(a);
|
||||||
}
|
}
|
||||||
|
@ -124,7 +120,15 @@ inline bool operator!=(const StorageImageLocation &a, const StorageImageLocation
|
||||||
return !(a == b);
|
return !(a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ImagePixOption {
|
namespace Images {
|
||||||
|
|
||||||
|
QImage prepareBlur(QImage image);
|
||||||
|
void prepareRound(QImage &image, ImageRoundRadius radius, ImageRoundCorners corners = ImageRoundCorner::All);
|
||||||
|
void prepareCircle(QImage &image);
|
||||||
|
QImage prepareColored(const style::color &add, QImage image);
|
||||||
|
QImage prepareOpaque(QImage image);
|
||||||
|
|
||||||
|
enum class Option {
|
||||||
None = 0x000,
|
None = 0x000,
|
||||||
Smooth = 0x001,
|
Smooth = 0x001,
|
||||||
Blurred = 0x002,
|
Blurred = 0x002,
|
||||||
|
@ -137,16 +141,22 @@ enum class ImagePixOption {
|
||||||
RoundedBottomRight = 0x100,
|
RoundedBottomRight = 0x100,
|
||||||
Colored = 0x200,
|
Colored = 0x200,
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(ImagePixOptions, ImagePixOption);
|
Q_DECLARE_FLAGS(Options, Option);
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(ImagePixOptions);
|
Q_DECLARE_OPERATORS_FOR_FLAGS(Options);
|
||||||
QPixmap imagePix(QImage img, int w, int h, ImagePixOptions options, int outerw, int outerh);
|
|
||||||
|
QImage prepare(QImage img, int w, int h, Options options, int outerw, int outerh);
|
||||||
|
|
||||||
|
inline QPixmap pixmap(QImage img, int w, int h, Options options, int outerw, int outerh) {
|
||||||
|
return QPixmap::fromImage(prepare(img, w, h, options, outerw, outerh), Qt::ColorOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Images
|
||||||
|
|
||||||
class DelayedStorageImage;
|
class DelayedStorageImage;
|
||||||
|
|
||||||
class HistoryItem;
|
class HistoryItem;
|
||||||
class Image {
|
class Image {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Image(const QString &file, QByteArray format = QByteArray());
|
Image(const QString &file, QByteArray format = QByteArray());
|
||||||
Image(const QByteArray &filecontent, QByteArray format = QByteArray());
|
Image(const QByteArray &filecontent, QByteArray format = QByteArray());
|
||||||
Image(const QPixmap &pixmap, QByteArray format = QByteArray());
|
Image(const QPixmap &pixmap, QByteArray format = QByteArray());
|
||||||
|
@ -183,7 +193,7 @@ public:
|
||||||
const QPixmap &pixBlurredColored(const style::color &add, int32 w = 0, int32 h = 0) const;
|
const QPixmap &pixBlurredColored(const style::color &add, int32 w = 0, int32 h = 0) const;
|
||||||
const QPixmap &pixSingle(int32 w, int32 h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners = ImageRoundCorner::All) const;
|
const QPixmap &pixSingle(int32 w, int32 h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners = ImageRoundCorner::All) const;
|
||||||
const QPixmap &pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners = ImageRoundCorner::All) const;
|
const QPixmap &pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners = ImageRoundCorner::All) const;
|
||||||
QPixmap pixNoCache(int w = 0, int h = 0, ImagePixOptions options = 0, int outerw = -1, int outerh = -1) const;
|
QPixmap pixNoCache(int w = 0, int h = 0, Images::Options options = 0, int outerw = -1, int outerh = -1) const;
|
||||||
QPixmap pixColoredNoCache(const style::color &add, int32 w = 0, int32 h = 0, bool smooth = false) const;
|
QPixmap pixColoredNoCache(const style::color &add, int32 w = 0, int32 h = 0, bool smooth = false) const;
|
||||||
QPixmap pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h = 0) const;
|
QPixmap pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h = 0) const;
|
||||||
|
|
||||||
|
|
|
@ -160,13 +160,6 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointer<TWidget> weakThis() {
|
|
||||||
return QPointer<TWidget>(this);
|
|
||||||
}
|
|
||||||
QPointer<const TWidget> weakThis() const {
|
|
||||||
return QPointer<const TWidget>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the size of the widget as it should be.
|
// Get the size of the widget as it should be.
|
||||||
// Negative return value means no default width.
|
// Negative return value means no default width.
|
||||||
virtual int naturalWidth() const {
|
virtual int naturalWidth() const {
|
||||||
|
@ -205,6 +198,18 @@ protected:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Widget>
|
||||||
|
class WeakPointed {
|
||||||
|
public:
|
||||||
|
QPointer<Widget> weak() {
|
||||||
|
return QPointer<Widget>(static_cast<Widget*>(this));
|
||||||
|
}
|
||||||
|
QPointer<const Widget> weak() const {
|
||||||
|
return QPointer<const Widget>(static_cast<const Widget*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
void myEnsureResized(QWidget *target);
|
void myEnsureResized(QWidget *target);
|
||||||
QPixmap myGrab(TWidget *target, QRect rect = QRect());
|
QPixmap myGrab(TWidget *target, QRect rect = QRect());
|
||||||
QImage myGrabImage(TWidget *target, QRect rect = QRect());
|
QImage myGrabImage(TWidget *target, QRect rect = QRect());
|
||||||
|
|
|
@ -488,7 +488,7 @@ defaultLinkButton: LinkButton {
|
||||||
|
|
||||||
defaultRippleAnimation: RippleAnimation {
|
defaultRippleAnimation: RippleAnimation {
|
||||||
color: windowBgRipple;
|
color: windowBgRipple;
|
||||||
showDuration: 200;
|
showDuration: 450;
|
||||||
hideDuration: 200;
|
hideDuration: 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,30 +101,23 @@ void TopBarWidget::showMenu() {
|
||||||
if (auto peer = main->peer()) {
|
if (auto peer = main->peer()) {
|
||||||
if (!_menu) {
|
if (!_menu) {
|
||||||
_menu.create(App::main());
|
_menu.create(App::main());
|
||||||
struct Data {
|
_menu->setHiddenCallback([that = weak(), menu = _menu.ptr()] {
|
||||||
Ui::DropdownMenu *menu = nullptr;
|
menu->deleteLater();
|
||||||
QPointer<TWidget> that;
|
if (that && that->_menu == menu) {
|
||||||
};
|
that->_menu = nullptr;
|
||||||
auto data = MakeShared<Data>();
|
that->_menuToggle->setForceRippled(false);
|
||||||
data->that = weakThis();
|
|
||||||
data->menu = _menu.ptr();
|
|
||||||
_menu->setHiddenCallback([this, data] {
|
|
||||||
data->menu->deleteLater();
|
|
||||||
if (data->that && _menu == data->menu) {
|
|
||||||
_menu = nullptr;
|
|
||||||
_menuToggle->setForceRippled(false);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_menu->setShowStartCallback([this, data] {
|
_menu->setShowStartCallback(base::lambda_guarded(this, [this, menu = _menu.ptr()] {
|
||||||
if (data->that && _menu == data->menu) {
|
if (_menu == menu) {
|
||||||
_menuToggle->setForceRippled(true);
|
_menuToggle->setForceRippled(true);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
_menu->setHideStartCallback([this, data] {
|
_menu->setHideStartCallback(base::lambda_guarded(this, [this, menu = _menu.ptr()] {
|
||||||
if (data->that && _menu == data->menu) {
|
if (_menu == menu) {
|
||||||
_menuToggle->setForceRippled(false);
|
_menuToggle->setForceRippled(false);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
_menuToggle->installEventFilter(_menu);
|
_menuToggle->installEventFilter(_menu);
|
||||||
App::main()->fillPeerMenu(peer, [this](const QString &text, base::lambda<void()> &&callback) {
|
App::main()->fillPeerMenu(peer, [this](const QString &text, base::lambda<void()> &&callback) {
|
||||||
return _menu->addAction(text, std_::move(callback));
|
return _menu->addAction(text, std_::move(callback));
|
||||||
|
|
|
@ -31,7 +31,7 @@ class DropdownMenu;
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
|
||||||
class TopBarWidget : public TWidget, private base::Subscriber {
|
class TopBarWidget : public TWidget, private base::Subscriber, public WeakPointed<TopBarWidget> {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -3,4 +3,4 @@ AppVersionStrMajor 0.10
|
||||||
AppVersionStrSmall 0.10.20
|
AppVersionStrSmall 0.10.20
|
||||||
AppVersionStr 0.10.20
|
AppVersionStr 0.10.20
|
||||||
AlphaChannel 0
|
AlphaChannel 0
|
||||||
BetaVersion 10019009
|
BetaVersion 10019010
|
||||||
|
|
|
@ -187,10 +187,10 @@
|
||||||
'<(src_loc)/boxes/passcodebox.h',
|
'<(src_loc)/boxes/passcodebox.h',
|
||||||
'<(src_loc)/boxes/photocropbox.cpp',
|
'<(src_loc)/boxes/photocropbox.cpp',
|
||||||
'<(src_loc)/boxes/photocropbox.h',
|
'<(src_loc)/boxes/photocropbox.h',
|
||||||
'<(src_loc)/boxes/photosendbox.cpp',
|
|
||||||
'<(src_loc)/boxes/photosendbox.h',
|
|
||||||
'<(src_loc)/boxes/report_box.cpp',
|
'<(src_loc)/boxes/report_box.cpp',
|
||||||
'<(src_loc)/boxes/report_box.h',
|
'<(src_loc)/boxes/report_box.h',
|
||||||
|
'<(src_loc)/boxes/send_files_box.cpp',
|
||||||
|
'<(src_loc)/boxes/send_files_box.h',
|
||||||
'<(src_loc)/boxes/sessionsbox.cpp',
|
'<(src_loc)/boxes/sessionsbox.cpp',
|
||||||
'<(src_loc)/boxes/sessionsbox.h',
|
'<(src_loc)/boxes/sessionsbox.h',
|
||||||
'<(src_loc)/boxes/sharebox.cpp',
|
'<(src_loc)/boxes/sharebox.cpp',
|
||||||
|
@ -364,6 +364,8 @@
|
||||||
'<(src_loc)/platform/linux/main_window_linux.h',
|
'<(src_loc)/platform/linux/main_window_linux.h',
|
||||||
'<(src_loc)/platform/linux/notifications_manager_linux.cpp',
|
'<(src_loc)/platform/linux/notifications_manager_linux.cpp',
|
||||||
'<(src_loc)/platform/linux/notifications_manager_linux.h',
|
'<(src_loc)/platform/linux/notifications_manager_linux.h',
|
||||||
|
'<(src_loc)/platform/mac/file_dialog_mac.mm',
|
||||||
|
'<(src_loc)/platform/mac/file_dialog_mac.h',
|
||||||
'<(src_loc)/platform/mac/mac_utilities.mm',
|
'<(src_loc)/platform/mac/mac_utilities.mm',
|
||||||
'<(src_loc)/platform/mac/mac_utilities.h',
|
'<(src_loc)/platform/mac/mac_utilities.h',
|
||||||
'<(src_loc)/platform/mac/main_window_mac.mm',
|
'<(src_loc)/platform/mac/main_window_mac.mm',
|
||||||
|
|
Loading…
Reference in New Issue