New profile photo edit by drag-n-drop. Animated photo button.
This commit is contained in:
		
							parent
							
								
									329285a8a6
								
							
						
					
					
						commit
						3570a1cf91
					
				
					 26 changed files with 531 additions and 147 deletions
				
			
		| 
						 | 
					@ -459,6 +459,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 | 
				
			||||||
"lng_profile_copy_fullname" = "Copy name";
 | 
					"lng_profile_copy_fullname" = "Copy name";
 | 
				
			||||||
"lng_profile_drop_area_title" = "Drop your image here";
 | 
					"lng_profile_drop_area_title" = "Drop your image here";
 | 
				
			||||||
"lng_profile_drop_area_subtitle" = "to set it as a group photo";
 | 
					"lng_profile_drop_area_subtitle" = "to set it as a group photo";
 | 
				
			||||||
 | 
					"lng_profile_drop_area_subtitle_channel" = "to set it as a channel photo";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"lng_channel_add_admins" = "New administrator";
 | 
					"lng_channel_add_admins" = "New administrator";
 | 
				
			||||||
"lng_channel_add_members" = "Add members";
 | 
					"lng_channel_add_members" = "Add members";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2304,6 +2304,10 @@ namespace {
 | 
				
			||||||
		return result;
 | 
							return result;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QPixmap pixmapFromImageInPlace(QImage &&image) {
 | 
				
			||||||
 | 
							return QPixmap::fromImage(std_::forward<QImage>(image), Qt::ColorOnly);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void regPhotoItem(PhotoData *data, HistoryItem *item) {
 | 
						void regPhotoItem(PhotoData *data, HistoryItem *item) {
 | 
				
			||||||
		::photoItems[data].insert(item, NullType());
 | 
							::photoItems[data].insert(item, NullType());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -234,6 +234,7 @@ namespace App {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QImage readImage(QByteArray data, QByteArray *format = 0, bool opaque = true, bool *animated = 0);
 | 
						QImage readImage(QByteArray data, QByteArray *format = 0, bool opaque = true, bool *animated = 0);
 | 
				
			||||||
	QImage readImage(const QString &file, QByteArray *format = 0, bool opaque = true, bool *animated = 0, QByteArray *content = 0);
 | 
						QImage readImage(const QString &file, QByteArray *format = 0, bool opaque = true, bool *animated = 0, QByteArray *content = 0);
 | 
				
			||||||
 | 
						QPixmap pixmapFromImageInPlace(QImage &&image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void regPhotoItem(PhotoData *data, HistoryItem *item);
 | 
						void regPhotoItem(PhotoData *data, HistoryItem *item);
 | 
				
			||||||
	void unregPhotoItem(PhotoData *data, HistoryItem *item);
 | 
						void unregPhotoItem(PhotoData *data, HistoryItem *item);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -109,10 +109,9 @@ void AboutBox::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
 | 
					#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
 | 
				
			||||||
QString _getCrashReportFile(const QMimeData *m) {
 | 
					QString _getCrashReportFile(const QMimeData *m) {
 | 
				
			||||||
	if (!m || m->urls().size() != 1) return QString();
 | 
						if (!m || m->urls().size() != 1 || !m->urls().at(0).isLocalFile()) return QString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QString file(m->urls().at(0).toLocalFile());
 | 
						auto file = psConvertFileUrl(m->urls().at(0));
 | 
				
			||||||
	if (file.startsWith(qsl("/.file/id="))) file = psConvertFileUrl(file);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return file.endsWith(qstr(".telegramcrash"), Qt::CaseInsensitive) ? file : QString();
 | 
						return file.endsWith(qstr(".telegramcrash"), Qt::CaseInsensitive) ? file : QString();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5590,8 +5590,7 @@ 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		QString file(i->toLocalFile());
 | 
							auto file = psConvertFileUrl(*i);
 | 
				
			||||||
		if (file.startsWith(qsl("/.file/id="))) file = psConvertFileUrl(file);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		QFileInfo info(file);
 | 
							QFileInfo info(file);
 | 
				
			||||||
		if (info.isDir()) return DragStateNone;
 | 
							if (info.isDir()) return DragStateNone;
 | 
				
			||||||
| 
						 | 
					@ -8420,8 +8419,7 @@ QStringList HistoryWidget::getMediasFromMime(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 QStringList();
 | 
							if (!i->isLocalFile()) return QStringList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		QString file(i->toLocalFile());
 | 
							auto file = psConvertFileUrl(*i);
 | 
				
			||||||
		if (file.startsWith(qsl("/.file/id="))) file = psConvertFileUrl(file);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		QFileInfo info(file);
 | 
							QFileInfo info(file);
 | 
				
			||||||
		uint64 s = info.size();
 | 
							uint64 s = info.size();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -216,9 +216,8 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
 | 
				
			||||||
	if (_delete && p == _delete) {
 | 
						if (_delete && p == _delete) {
 | 
				
			||||||
		bool wasactive = (_state & StateFlag::DeleteOver);
 | 
							bool wasactive = (_state & StateFlag::DeleteOver);
 | 
				
			||||||
		if (active != wasactive) {
 | 
							if (active != wasactive) {
 | 
				
			||||||
			float64 from = active ? 0 : 1, to = active ? 1 : 0;
 | 
								auto from = active ? 0. : 1., to = active ? 1. : 0.;
 | 
				
			||||||
			EnsureAnimation(_a_deleteOver, from, func(this, &Gif::update));
 | 
								START_ANIMATION(_a_deleteOver, func(this, &Gif::update), from, to, st::stickersRowDuration, anim::linear);
 | 
				
			||||||
			_a_deleteOver.start(to, st::stickersRowDuration);
 | 
					 | 
				
			||||||
			if (active) {
 | 
								if (active) {
 | 
				
			||||||
				_state |= StateFlag::DeleteOver;
 | 
									_state |= StateFlag::DeleteOver;
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
| 
						 | 
					@ -231,9 +230,8 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
 | 
				
			||||||
		if (active != wasactive) {
 | 
							if (active != wasactive) {
 | 
				
			||||||
			if (!getShownDocument()->loaded()) {
 | 
								if (!getShownDocument()->loaded()) {
 | 
				
			||||||
				ensureAnimation();
 | 
									ensureAnimation();
 | 
				
			||||||
				float64 from = active ? 0 : 1, to = active ? 1 : 0;
 | 
									auto from = active ? 0. : 1., to = active ? 1. : 0.;
 | 
				
			||||||
				EnsureAnimation(_animation->_a_over, from, func(this, &Gif::update));
 | 
									START_ANIMATION(_animation->_a_over, func(this, &Gif::update), from, to, st::stickersRowDuration, anim::linear);
 | 
				
			||||||
				_animation->_a_over.start(to, st::stickersRowDuration);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (active) {
 | 
								if (active) {
 | 
				
			||||||
				_state |= StateFlag::Over;
 | 
									_state |= StateFlag::Over;
 | 
				
			||||||
| 
						 | 
					@ -413,9 +411,8 @@ void Sticker::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
 | 
				
			||||||
		if (active != _active) {
 | 
							if (active != _active) {
 | 
				
			||||||
			_active = active;
 | 
								_active = active;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			float64 from = _active ? 0 : 1, to = _active ? 1 : 0;
 | 
								auto from = active ? 0. : 1., to = active ? 1. : 0.;
 | 
				
			||||||
			EnsureAnimation(_a_over, from, func(this, &Sticker::update));
 | 
								START_ANIMATION(_a_over, func(this, &Sticker::update), from, to, st::stickersRowDuration, anim::linear);
 | 
				
			||||||
			_a_over.start(to, st::stickersRowDuration);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ItemBase::clickHandlerActiveChanged(p, active);
 | 
						ItemBase::clickHandlerActiveChanged(p, active);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,7 @@ profileTopBarBackPosition: point(32px, 17px);
 | 
				
			||||||
profileMarginTop: 13px;
 | 
					profileMarginTop: 13px;
 | 
				
			||||||
profilePhotoSize: 112px;
 | 
					profilePhotoSize: 112px;
 | 
				
			||||||
profilePhotoLeft: 35px;
 | 
					profilePhotoLeft: 35px;
 | 
				
			||||||
 | 
					profilePhotoDuration: 500;
 | 
				
			||||||
profileNameLeft: 26px;
 | 
					profileNameLeft: 26px;
 | 
				
			||||||
profileNameTop: 9px;
 | 
					profileNameTop: 9px;
 | 
				
			||||||
profileNameLabel: flatLabel(labelDefFlat) {
 | 
					profileNameLabel: flatLabel(labelDefFlat) {
 | 
				
			||||||
| 
						 | 
					@ -78,13 +79,14 @@ profileSecondaryButton: BoxButton(profilePrimaryButton) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
profileDropAreaBg: profileBg;
 | 
					profileDropAreaBg: profileBg;
 | 
				
			||||||
profileDropAreaFg: #3fb0e4;
 | 
					profileDropAreaFg: #3fb0e4;
 | 
				
			||||||
profileDropAreaPadding: margins(30px, 20px, 30px, 20px);
 | 
					profileDropAreaPadding: margins(25px, 3px, 25px, 20px);
 | 
				
			||||||
profileDropAreaTitleFont: font(24px);
 | 
					profileDropAreaTitleFont: font(24px);
 | 
				
			||||||
profileDropAreaTitleTop: 36px;
 | 
					profileDropAreaTitleTop: 30px;
 | 
				
			||||||
profileDropAreaSubtitleFont: font(16px);
 | 
					profileDropAreaSubtitleFont: font(16px);
 | 
				
			||||||
profileDropAreaSubtitleTop: 72px;
 | 
					profileDropAreaSubtitleTop: 68px;
 | 
				
			||||||
profileDropAreaBorderFg: profileDropAreaFg;
 | 
					profileDropAreaBorderFg: profileDropAreaFg;
 | 
				
			||||||
profileDropAreaBorderWidth: 3px;
 | 
					profileDropAreaBorderWidth: 3px;
 | 
				
			||||||
 | 
					profileDropAreaDuration: 200;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
profileDividerFg: black;
 | 
					profileDividerFg: black;
 | 
				
			||||||
profileDividerLeft: icon {
 | 
					profileDividerLeft: icon {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 | 
				
			||||||
#include "profile/profile_cover.h"
 | 
					#include "profile/profile_cover.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "styles/style_profile.h"
 | 
					#include "styles/style_profile.h"
 | 
				
			||||||
 | 
					#include "profile/profile_cover_drop_area.h"
 | 
				
			||||||
 | 
					#include "profile/profile_userpic_button.h"
 | 
				
			||||||
#include "ui/buttons/round_button.h"
 | 
					#include "ui/buttons/round_button.h"
 | 
				
			||||||
#include "ui/filedialog.h"
 | 
					#include "ui/filedialog.h"
 | 
				
			||||||
#include "observer_peer.h"
 | 
					#include "observer_peer.h"
 | 
				
			||||||
| 
						 | 
					@ -71,109 +73,13 @@ const Notify::PeerUpdateFlags ButtonsUpdateFlags = Notify::PeerUpdateFlag::UserC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PhotoButton final : public Button, public Notify::Observer {
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	PhotoButton(QWidget *parent, PeerData *peer) : Button(parent), _peer(peer) {
 | 
					 | 
				
			||||||
		resize(st::profilePhotoSize, st::profilePhotoSize);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		processNewPeerPhoto();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Notify::registerPeerObserver(Notify::PeerUpdateFlag::PhotoChanged, this, &PhotoButton::notifyPeerUpdated);
 | 
					 | 
				
			||||||
		FileDownload::registerImageLoadedObserver(this, &PhotoButton::notifyImageLoaded);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
protected:
 | 
					 | 
				
			||||||
	void paintEvent(QPaintEvent *e) {
 | 
					 | 
				
			||||||
		Painter p(this);
 | 
					 | 
				
			||||||
		p.drawPixmap(0, 0, _userpic);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	void notifyPeerUpdated(const Notify::PeerUpdate &update) {
 | 
					 | 
				
			||||||
		if (update.peer != _peer) {
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		processNewPeerPhoto();
 | 
					 | 
				
			||||||
		this->update();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void notifyImageLoaded() {
 | 
					 | 
				
			||||||
		if (_waiting && _peer->userpicLoaded()) {
 | 
					 | 
				
			||||||
			_waiting = false;
 | 
					 | 
				
			||||||
			_userpic = _peer->genUserpic(st::profilePhotoSize);
 | 
					 | 
				
			||||||
			update();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void processNewPeerPhoto() {
 | 
					 | 
				
			||||||
		bool hasPhoto = (_peer->photoId && _peer->photoId != UnknownPeerPhotoId);
 | 
					 | 
				
			||||||
		setCursor(hasPhoto ? style::cur_pointer : style::cur_default);
 | 
					 | 
				
			||||||
		_waiting = !_peer->userpicLoaded();
 | 
					 | 
				
			||||||
		if (_waiting) {
 | 
					 | 
				
			||||||
			_peer->loadUserpic(true);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			_userpic = _peer->genUserpic(st::profilePhotoSize);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PeerData *_peer;
 | 
					 | 
				
			||||||
	bool _waiting = false;
 | 
					 | 
				
			||||||
	QPixmap _userpic;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class DropArea : public TWidget {
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	DropArea(QWidget *parent) : TWidget(parent) {
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void showAnimated() {
 | 
					 | 
				
			||||||
		show();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
protected:
 | 
					 | 
				
			||||||
	void paintEvent(QPaintEvent *e) override {
 | 
					 | 
				
			||||||
		Painter p(this);
 | 
					 | 
				
			||||||
		p.fillRect(e->rect(), st::profileDropAreaBg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (width() < st::profileDropAreaPadding.left() + st::profileDropAreaPadding.right()) return;
 | 
					 | 
				
			||||||
		if (height() < st::profileDropAreaPadding.top() + st::profileDropAreaPadding.bottom()) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto border = st::profileDropAreaBorderWidth;
 | 
					 | 
				
			||||||
		auto &borderFg = st::profileDropAreaBorderFg;
 | 
					 | 
				
			||||||
		auto inner = rect().marginsRemoved(st::profileDropAreaPadding);
 | 
					 | 
				
			||||||
		p.fillRect(inner.x(), inner.y(), inner.width(), border, borderFg);
 | 
					 | 
				
			||||||
		p.fillRect(inner.x(), inner.y() + inner.height() - border, inner.width(), border, borderFg);
 | 
					 | 
				
			||||||
		p.fillRect(inner.x(), inner.y() + border, border, inner.height() - 2 * border, borderFg);
 | 
					 | 
				
			||||||
		p.fillRect(inner.x() + inner.width() - border, inner.y() + border, border, inner.height() - 2 * border, borderFg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto title = lang(lng_profile_drop_area_title);
 | 
					 | 
				
			||||||
		int titleWidth = st::profileDropAreaTitleFont->width(title);
 | 
					 | 
				
			||||||
		int titleLeft = inner.x() + (inner.width() - titleWidth) / 2;
 | 
					 | 
				
			||||||
		int titleTop = inner.y() + st::profileDropAreaTitleTop + st::profileDropAreaTitleFont->ascent;
 | 
					 | 
				
			||||||
		p.setFont(st::profileDropAreaTitleFont);
 | 
					 | 
				
			||||||
		p.setPen(st::profileDropAreaFg);
 | 
					 | 
				
			||||||
		p.drawText(titleLeft, titleTop, title);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto subtitle = lang(lng_profile_drop_area_subtitle);
 | 
					 | 
				
			||||||
		int subtitleWidth = st::profileDropAreaSubtitleFont->width(subtitle);
 | 
					 | 
				
			||||||
		int subtitleLeft = inner.x() + (inner.width() - subtitleWidth) / 2;
 | 
					 | 
				
			||||||
		int subtitleTop = inner.y() + st::profileDropAreaSubtitleTop + st::profileDropAreaSubtitleFont->ascent;
 | 
					 | 
				
			||||||
		p.setFont(st::profileDropAreaSubtitleFont);
 | 
					 | 
				
			||||||
		p.setPen(st::profileDropAreaFg);
 | 
					 | 
				
			||||||
		p.drawText(subtitleLeft, subtitleTop, subtitle);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CoverWidget::CoverWidget(QWidget *parent, PeerData *peer) : TWidget(parent)
 | 
					CoverWidget::CoverWidget(QWidget *parent, PeerData *peer) : TWidget(parent)
 | 
				
			||||||
, _peer(peer)
 | 
					, _peer(peer)
 | 
				
			||||||
, _peerUser(peer->asUser())
 | 
					, _peerUser(peer->asUser())
 | 
				
			||||||
, _peerChat(peer->asChat())
 | 
					, _peerChat(peer->asChat())
 | 
				
			||||||
, _peerChannel(peer->asChannel())
 | 
					, _peerChannel(peer->asChannel())
 | 
				
			||||||
, _peerMegagroup(peer->isMegagroup() ? _peerChannel : nullptr)
 | 
					, _peerMegagroup(peer->isMegagroup() ? _peerChannel : nullptr)
 | 
				
			||||||
, _photoButton(this, peer)
 | 
					, _userpicButton(this, peer)
 | 
				
			||||||
, _name(this, QString(), st::profileNameLabel) {
 | 
					, _name(this, QString(), st::profileNameLabel) {
 | 
				
			||||||
	setAttribute(Qt::WA_OpaquePaintEvent);
 | 
						setAttribute(Qt::WA_OpaquePaintEvent);
 | 
				
			||||||
	setAcceptDrops(true);
 | 
						setAcceptDrops(true);
 | 
				
			||||||
| 
						 | 
					@ -185,7 +91,7 @@ CoverWidget::CoverWidget(QWidget *parent, PeerData *peer) : TWidget(parent)
 | 
				
			||||||
	Notify::registerPeerObserver(observeEvents, this, &CoverWidget::notifyPeerUpdated);
 | 
						Notify::registerPeerObserver(observeEvents, this, &CoverWidget::notifyPeerUpdated);
 | 
				
			||||||
	FileDialog::registerObserver(this, &CoverWidget::notifyFileQueryUpdated);
 | 
						FileDialog::registerObserver(this, &CoverWidget::notifyFileQueryUpdated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	connect(_photoButton, SIGNAL(clicked()), this, SLOT(onPhotoShow()));
 | 
						connect(_userpicButton, SIGNAL(clicked()), this, SLOT(onPhotoShow()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	refreshNameText();
 | 
						refreshNameText();
 | 
				
			||||||
	refreshStatusText();
 | 
						refreshStatusText();
 | 
				
			||||||
| 
						 | 
					@ -207,19 +113,19 @@ void CoverWidget::resizeToWidth(int newWidth) {
 | 
				
			||||||
	int newHeight = 0;
 | 
						int newHeight = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	newHeight += st::profileMarginTop;
 | 
						newHeight += st::profileMarginTop;
 | 
				
			||||||
	_photoButton->moveToLeft(st::profilePhotoLeft, newHeight);
 | 
						_userpicButton->moveToLeft(st::profilePhotoLeft, newHeight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int infoLeft = _photoButton->x() + _photoButton->width();
 | 
						int infoLeft = _userpicButton->x() + _userpicButton->width();
 | 
				
			||||||
	int nameLeft = infoLeft + st::profileNameLeft - st::profileNameLabel.margin.left();
 | 
						int nameLeft = infoLeft + st::profileNameLeft - st::profileNameLabel.margin.left();
 | 
				
			||||||
	int nameTop = _photoButton->y() + st::profileNameTop - st::profileNameLabel.margin.top();
 | 
						int nameTop = _userpicButton->y() + st::profileNameTop - st::profileNameLabel.margin.top();
 | 
				
			||||||
	_name.moveToLeft(nameLeft, nameTop);
 | 
						_name.moveToLeft(nameLeft, nameTop);
 | 
				
			||||||
	int nameWidth = width() - infoLeft - st::profileNameLeft - st::profileButtonSkip;
 | 
						int nameWidth = width() - infoLeft - st::profileNameLeft - st::profileButtonSkip;
 | 
				
			||||||
	nameWidth += st::profileNameLabel.margin.left() + st::profileNameLabel.margin.right();
 | 
						nameWidth += st::profileNameLabel.margin.left() + st::profileNameLabel.margin.right();
 | 
				
			||||||
	_name.resizeToWidth(nameWidth);
 | 
						_name.resizeToWidth(nameWidth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_statusPosition = QPoint(infoLeft + st::profileStatusLeft, _photoButton->y() + st::profileStatusTop);
 | 
						_statusPosition = QPoint(infoLeft + st::profileStatusLeft, _userpicButton->y() + st::profileStatusTop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int buttonLeft = st::profilePhotoLeft + _photoButton->width() + st::profileButtonLeft;
 | 
						int buttonLeft = st::profilePhotoLeft + _userpicButton->width() + st::profileButtonLeft;
 | 
				
			||||||
	for_const (auto button, _buttons) {
 | 
						for_const (auto button, _buttons) {
 | 
				
			||||||
		button->moveToLeft(buttonLeft, st::profileButtonTop);
 | 
							button->moveToLeft(buttonLeft, st::profileButtonTop);
 | 
				
			||||||
		buttonLeft += button->width() + st::profileButtonSkip;
 | 
							buttonLeft += button->width() + st::profileButtonSkip;
 | 
				
			||||||
| 
						 | 
					@ -233,10 +139,15 @@ void CoverWidget::resizeToWidth(int newWidth) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	newHeight += st::profileBlocksTop;
 | 
						newHeight += st::profileBlocksTop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resizeDropArea();
 | 
				
			||||||
	resize(newWidth, newHeight);
 | 
						resize(newWidth, newHeight);
 | 
				
			||||||
	update();
 | 
						update();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CoverWidget::showFinished() {
 | 
				
			||||||
 | 
						_userpicButton->showFinished();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CoverWidget::paintEvent(QPaintEvent *e) {
 | 
					void CoverWidget::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
	Painter p(this);
 | 
						Painter p(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -249,21 +160,109 @@ void CoverWidget::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
	paintDivider(p);
 | 
						paintDivider(p);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CoverWidget::dragEnterEvent(QDragEnterEvent *e) {
 | 
					void CoverWidget::resizeDropArea() {
 | 
				
			||||||
	_dropArea = new DropArea(this);
 | 
						if (_dropArea) {
 | 
				
			||||||
		_dropArea->setGeometry(0, 0, width(), _dividerTop);
 | 
							_dropArea->setGeometry(0, 0, width(), _dividerTop);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CoverWidget::dropAreaHidden(CoverDropArea *dropArea) {
 | 
				
			||||||
 | 
						if (_dropArea == dropArea) {
 | 
				
			||||||
 | 
							_dropArea->deleteLater();
 | 
				
			||||||
 | 
							_dropArea = nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CoverWidget::canEditPhoto() const {
 | 
				
			||||||
 | 
						if (_peerChat && _peerChat->canEdit()) {
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						} else if (_peerMegagroup && _peerMegagroup->canEditPhoto()) {
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						} else if (_peerChannel && _peerChannel->canEditPhoto()) {
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool CoverWidget::mimeDataHasImage(const QMimeData *mimeData) const {
 | 
				
			||||||
 | 
						if (!mimeData) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mimeData->hasImage()) return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto uriListFormat = qsl("text/uri-list");
 | 
				
			||||||
 | 
						if (!mimeData->hasFormat(uriListFormat)) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto &urls = mimeData->urls();
 | 
				
			||||||
 | 
						if (urls.size() != 1) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto &url = urls.at(0);
 | 
				
			||||||
 | 
						if (!url.isLocalFile()) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto file = psConvertFileUrl(url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QFileInfo info(file);
 | 
				
			||||||
 | 
						if (info.isDir()) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						quint64 s = info.size();
 | 
				
			||||||
 | 
						if (s >= MaxUploadDocumentSize) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto &ext : cImgExtensions()) {
 | 
				
			||||||
 | 
							if (file.endsWith(ext, Qt::CaseInsensitive)) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CoverWidget::dragEnterEvent(QDragEnterEvent *e) {
 | 
				
			||||||
 | 
						if (!canEditPhoto() || !mimeDataHasImage(e->mimeData())) {
 | 
				
			||||||
 | 
							e->ignore();
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!_dropArea) {
 | 
				
			||||||
 | 
							auto title = lang(lng_profile_drop_area_title);
 | 
				
			||||||
 | 
							QString subtitle;
 | 
				
			||||||
 | 
							if (_peerChat || _peerMegagroup) {
 | 
				
			||||||
 | 
								subtitle = lang(lng_profile_drop_area_subtitle);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								subtitle = lang(lng_profile_drop_area_subtitle_channel);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_dropArea = new CoverDropArea(this, title, subtitle);
 | 
				
			||||||
 | 
							resizeDropArea();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	_dropArea->showAnimated();
 | 
						_dropArea->showAnimated();
 | 
				
			||||||
 | 
						e->setDropAction(Qt::CopyAction);
 | 
				
			||||||
	e->accept();
 | 
						e->accept();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) {
 | 
					void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) {
 | 
				
			||||||
	delete _dropArea;
 | 
						if (_dropArea && !_dropArea->hiding()) {
 | 
				
			||||||
	_dropArea = nullptr;
 | 
							_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CoverWidget::dropEvent(QDropEvent *e) {
 | 
					void CoverWidget::dropEvent(QDropEvent *e) {
 | 
				
			||||||
	delete _dropArea;
 | 
						auto mimeData = e->mimeData();
 | 
				
			||||||
	_dropArea = nullptr;
 | 
					
 | 
				
			||||||
 | 
						QImage img;
 | 
				
			||||||
 | 
						if (mimeData->hasImage()) {
 | 
				
			||||||
 | 
							img = qvariant_cast<QImage>(mimeData->imageData());
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							auto &urls = mimeData->urls();
 | 
				
			||||||
 | 
							if (urls.size() == 1) {
 | 
				
			||||||
 | 
								auto &url = urls.at(0);
 | 
				
			||||||
 | 
								if (url.isLocalFile()) {
 | 
				
			||||||
 | 
									img = App::readImage(psConvertFileUrl(url));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!_dropArea->hiding()) {
 | 
				
			||||||
 | 
							_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e->acceptProposedAction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						showSetPhotoBox(img);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CoverWidget::paintDivider(Painter &p) {
 | 
					void CoverWidget::paintDivider(Painter &p) {
 | 
				
			||||||
| 
						 | 
					@ -439,6 +438,10 @@ void CoverWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update)
 | 
				
			||||||
		img = App::readImage(update.filePaths.front());
 | 
							img = App::readImage(update.filePaths.front());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						showSetPhotoBox(img);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CoverWidget::showSetPhotoBox(const QImage &img) {
 | 
				
			||||||
	if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) {
 | 
						if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) {
 | 
				
			||||||
		Ui::showLayer(new InformBox(lang(lng_bad_photo)));
 | 
							Ui::showLayer(new InformBox(lang(lng_bad_photo)));
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,8 +35,8 @@ struct PeerUpdate;
 | 
				
			||||||
namespace Profile {
 | 
					namespace Profile {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BackButton;
 | 
					class BackButton;
 | 
				
			||||||
class PhotoButton;
 | 
					class UserpicButton;
 | 
				
			||||||
class DropArea;
 | 
					class CoverDropArea;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CoverWidget final : public TWidget, public Notify::Observer {
 | 
					class CoverWidget final : public TWidget, public Notify::Observer {
 | 
				
			||||||
	Q_OBJECT
 | 
						Q_OBJECT
 | 
				
			||||||
| 
						 | 
					@ -47,6 +47,8 @@ public:
 | 
				
			||||||
	// Count new height for width=newWidth and resize to it.
 | 
						// Count new height for width=newWidth and resize to it.
 | 
				
			||||||
	void resizeToWidth(int newWidth);
 | 
						void resizeToWidth(int newWidth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void showFinished();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
	void onPhotoShow();
 | 
						void onPhotoShow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,14 +85,20 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void paintDivider(Painter &p);
 | 
						void paintDivider(Painter &p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool canEditPhoto() const;
 | 
				
			||||||
 | 
						void showSetPhotoBox(const QImage &img);
 | 
				
			||||||
 | 
						void resizeDropArea();
 | 
				
			||||||
 | 
						void dropAreaHidden(CoverDropArea *dropArea);
 | 
				
			||||||
 | 
						bool mimeDataHasImage(const QMimeData *mimeData) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PeerData *_peer;
 | 
						PeerData *_peer;
 | 
				
			||||||
	UserData *_peerUser;
 | 
						UserData *_peerUser;
 | 
				
			||||||
	ChatData *_peerChat;
 | 
						ChatData *_peerChat;
 | 
				
			||||||
	ChannelData *_peerChannel;
 | 
						ChannelData *_peerChannel;
 | 
				
			||||||
	ChannelData *_peerMegagroup;
 | 
						ChannelData *_peerMegagroup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ChildWidget<PhotoButton> _photoButton;
 | 
						ChildWidget<UserpicButton> _userpicButton;
 | 
				
			||||||
	ChildWidget<DropArea> _dropArea = { nullptr };
 | 
						ChildWidget<CoverDropArea> _dropArea = { nullptr };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FlatLabel _name;
 | 
						FlatLabel _name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										99
									
								
								Telegram/SourceFiles/profile/profile_cover_drop_area.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Telegram/SourceFiles/profile/profile_cover_drop_area.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,99 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					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 "profile/profile_cover_drop_area.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "styles/style_profile.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Profile {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CoverDropArea::CoverDropArea(QWidget *parent, const QString &title, const QString &subtitle) : TWidget(parent)
 | 
				
			||||||
 | 
					, _title(title)
 | 
				
			||||||
 | 
					, _subtitle(subtitle)
 | 
				
			||||||
 | 
					, _titleWidth(st::profileDropAreaTitleFont->width(_title))
 | 
				
			||||||
 | 
					, _subtitleWidth(st::profileDropAreaSubtitleFont->width(_subtitle)) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CoverDropArea::showAnimated() {
 | 
				
			||||||
 | 
						show();
 | 
				
			||||||
 | 
						_hiding = false;
 | 
				
			||||||
 | 
						setupAnimation();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CoverDropArea::hideAnimated(HideFinishCallback &&callback) {
 | 
				
			||||||
 | 
						_hideFinishCallback = std_::move(callback);
 | 
				
			||||||
 | 
						_hiding = true;
 | 
				
			||||||
 | 
						setupAnimation();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CoverDropArea::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
 | 
						Painter p(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (_a_appearance.animating(getms())) {
 | 
				
			||||||
 | 
							p.setOpacity(_a_appearance.current());
 | 
				
			||||||
 | 
							p.drawPixmap(0, 0, _cache);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!_cache.isNull()) {
 | 
				
			||||||
 | 
							_cache = QPixmap();
 | 
				
			||||||
 | 
							if (_hiding) {
 | 
				
			||||||
 | 
								hide();
 | 
				
			||||||
 | 
								_hideFinishCallback.call(this);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p.fillRect(e->rect(), st::profileDropAreaBg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (width() < st::profileDropAreaPadding.left() + st::profileDropAreaPadding.right()) return;
 | 
				
			||||||
 | 
						if (height() < st::profileDropAreaPadding.top() + st::profileDropAreaPadding.bottom()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto border = st::profileDropAreaBorderWidth;
 | 
				
			||||||
 | 
						auto &borderFg = st::profileDropAreaBorderFg;
 | 
				
			||||||
 | 
						auto inner = rect().marginsRemoved(st::profileDropAreaPadding);
 | 
				
			||||||
 | 
						p.fillRect(inner.x(), inner.y(), inner.width(), border, borderFg);
 | 
				
			||||||
 | 
						p.fillRect(inner.x(), inner.y() + inner.height() - border, inner.width(), border, borderFg);
 | 
				
			||||||
 | 
						p.fillRect(inner.x(), inner.y() + border, border, inner.height() - 2 * border, borderFg);
 | 
				
			||||||
 | 
						p.fillRect(inner.x() + inner.width() - border, inner.y() + border, border, inner.height() - 2 * border, borderFg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int titleLeft = inner.x() + (inner.width() - _titleWidth) / 2;
 | 
				
			||||||
 | 
						int titleTop = inner.y() + st::profileDropAreaTitleTop + st::profileDropAreaTitleFont->ascent;
 | 
				
			||||||
 | 
						p.setFont(st::profileDropAreaTitleFont);
 | 
				
			||||||
 | 
						p.setPen(st::profileDropAreaFg);
 | 
				
			||||||
 | 
						p.drawText(titleLeft, titleTop, _title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int subtitleLeft = inner.x() + (inner.width() - _subtitleWidth) / 2;
 | 
				
			||||||
 | 
						int subtitleTop = inner.y() + st::profileDropAreaSubtitleTop + st::profileDropAreaSubtitleFont->ascent;
 | 
				
			||||||
 | 
						p.setFont(st::profileDropAreaSubtitleFont);
 | 
				
			||||||
 | 
						p.setPen(st::profileDropAreaFg);
 | 
				
			||||||
 | 
						p.drawText(subtitleLeft, subtitleTop, _subtitle);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CoverDropArea::setupAnimation() {
 | 
				
			||||||
 | 
						if (_cache.isNull()) {
 | 
				
			||||||
 | 
							_cache = myGrab(this);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						auto from = _hiding ? 1. : 0., to = _hiding ? 0. : 1.;
 | 
				
			||||||
 | 
						START_ANIMATION(_a_appearance, func(this, &CoverDropArea::refreshCallback), from, to, st::profileDropAreaDuration, anim::linear);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Profile
 | 
				
			||||||
							
								
								
									
										57
									
								
								Telegram/SourceFiles/profile/profile_cover_drop_area.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								Telegram/SourceFiles/profile/profile_cover_drop_area.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,57 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					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 Profile {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CoverDropArea : public TWidget {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						CoverDropArea(QWidget *parent, const QString &title, const QString &subtitle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void showAnimated();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						using HideFinishCallback = Function<void, CoverDropArea*>;
 | 
				
			||||||
 | 
						void hideAnimated(HideFinishCallback &&callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool hiding() const {
 | 
				
			||||||
 | 
							return _hiding;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						void paintEvent(QPaintEvent *e) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						void refreshCallback() {
 | 
				
			||||||
 | 
							update();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						void setupAnimation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QString _title, _subtitle;
 | 
				
			||||||
 | 
						int _titleWidth, _subtitleWidth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QPixmap _cache;
 | 
				
			||||||
 | 
						FloatAnimation _a_appearance;
 | 
				
			||||||
 | 
						bool _hiding = false;
 | 
				
			||||||
 | 
						HideFinishCallback _hideFinishCallback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Profile
 | 
				
			||||||
| 
						 | 
					@ -97,7 +97,6 @@ void FixedBar::onDeleteContact() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
void FixedBar::resizeToWidth(int newWidth) {
 | 
					void FixedBar::resizeToWidth(int newWidth) {
 | 
				
			||||||
	int newHeight = 0;
 | 
						int newHeight = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +56,10 @@ void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InnerWidget::showFinished() {
 | 
				
			||||||
 | 
						_cover->showFinished();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void InnerWidget::decreaseAdditionalHeight(int removeHeight) {
 | 
					void InnerWidget::decreaseAdditionalHeight(int removeHeight) {
 | 
				
			||||||
	resizeToWidth(width(), height() - removeHeight);
 | 
						resizeToWidth(width(), height() - removeHeight);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,6 +41,8 @@ public:
 | 
				
			||||||
	// Updates the area that is visible inside the scroll container.
 | 
						// Updates the area that is visible inside the scroll container.
 | 
				
			||||||
	void setVisibleTopBottom(int visibleTop, int visibleBottom);
 | 
						void setVisibleTopBottom(int visibleTop, int visibleBottom);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void showFinished();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
signals:
 | 
					signals:
 | 
				
			||||||
	void cancelled();
 | 
						void cancelled();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										117
									
								
								Telegram/SourceFiles/profile/profile_userpic_button.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								Telegram/SourceFiles/profile/profile_userpic_button.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,117 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					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 "profile/profile_userpic_button.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "styles/style_profile.h"
 | 
				
			||||||
 | 
					#include "observer_peer.h"
 | 
				
			||||||
 | 
					#include "mtproto/file_download.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Profile {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UserpicButton::UserpicButton(QWidget *parent, PeerData *peer) : Button(parent), _peer(peer) {
 | 
				
			||||||
 | 
						resize(st::profilePhotoSize, st::profilePhotoSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						processPeerPhoto();
 | 
				
			||||||
 | 
						_notShownYet = _waiting;
 | 
				
			||||||
 | 
						if (!_waiting) {
 | 
				
			||||||
 | 
							_userpic = prepareUserpicPixmap();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Notify::registerPeerObserver(Notify::PeerUpdateFlag::PhotoChanged, this, &UserpicButton::notifyPeerUpdated);
 | 
				
			||||||
 | 
						FileDownload::registerImageLoadedObserver(this, &UserpicButton::notifyImageLoaded);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::showFinished() {
 | 
				
			||||||
 | 
						if (_notShownYet && !_waiting) {
 | 
				
			||||||
 | 
							_notShownYet = false;
 | 
				
			||||||
 | 
							_a_appearance.finish();
 | 
				
			||||||
 | 
							START_ANIMATION(_a_appearance, func(this, &UserpicButton::refreshCallback), 0, 1, st::profilePhotoDuration, anim::linear);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
 | 
						Painter p(this);
 | 
				
			||||||
 | 
						if (_a_appearance.animating(getms())) {
 | 
				
			||||||
 | 
							p.drawPixmap(0, 0, _oldUserpic);
 | 
				
			||||||
 | 
							p.setOpacity(_a_appearance.current());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p.drawPixmap(0, 0, _userpic);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::notifyPeerUpdated(const Notify::PeerUpdate &update) {
 | 
				
			||||||
 | 
						if (update.peer != _peer) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						processNewPeerPhoto();
 | 
				
			||||||
 | 
						this->update();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::notifyImageLoaded() {
 | 
				
			||||||
 | 
						if (_waiting && _peer->userpicLoaded()) {
 | 
				
			||||||
 | 
							_waiting = false;
 | 
				
			||||||
 | 
							startNewPhotoShowing();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::processPeerPhoto() {
 | 
				
			||||||
 | 
						bool hasPhoto = (_peer->photoId && _peer->photoId != UnknownPeerPhotoId);
 | 
				
			||||||
 | 
						setCursor(hasPhoto ? style::cur_pointer : style::cur_default);
 | 
				
			||||||
 | 
						_waiting = !_peer->userpicLoaded();
 | 
				
			||||||
 | 
						if (_waiting) {
 | 
				
			||||||
 | 
							_peer->loadUserpic(true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::processNewPeerPhoto() {
 | 
				
			||||||
 | 
						processPeerPhoto();
 | 
				
			||||||
 | 
						if (!_waiting) {
 | 
				
			||||||
 | 
							startNewPhotoShowing();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::startNewPhotoShowing() {
 | 
				
			||||||
 | 
						_oldUserpic = myGrab(this);
 | 
				
			||||||
 | 
						_userpic = prepareUserpicPixmap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (_notShownYet) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_a_appearance.finish();
 | 
				
			||||||
 | 
						START_ANIMATION(_a_appearance, func(this, &UserpicButton::refreshCallback), 0, 1, st::profilePhotoDuration, anim::linear);
 | 
				
			||||||
 | 
						update();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QPixmap UserpicButton::prepareUserpicPixmap() const {
 | 
				
			||||||
 | 
						auto retina = cIntRetinaFactor();
 | 
				
			||||||
 | 
						auto size = st::profilePhotoSize * retina;
 | 
				
			||||||
 | 
						QImage image(size, size, QImage::Format_ARGB32_Premultiplied);
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Painter p(&image);
 | 
				
			||||||
 | 
							p.fillRect(0, 0, size, size, st::profileBg);
 | 
				
			||||||
 | 
							_peer->paintUserpic(p, st::profilePhotoSize, 0, 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return App::pixmapFromImageInPlace(std_::move(image));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Profile
 | 
				
			||||||
							
								
								
									
										64
									
								
								Telegram/SourceFiles/profile/profile_userpic_button.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Telegram/SourceFiles/profile/profile_userpic_button.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core/observer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Notify {
 | 
				
			||||||
 | 
					struct PeerUpdate;
 | 
				
			||||||
 | 
					} // namespace Notify
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Profile {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UserpicButton final : public Button, public Notify::Observer {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						UserpicButton(QWidget *parent, PeerData *peer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If at the first moment the _userpic was not loaded,
 | 
				
			||||||
 | 
						// we need to show it animated after the profile is fully shown.
 | 
				
			||||||
 | 
						void showFinished();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						void paintEvent(QPaintEvent *e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						void notifyPeerUpdated(const Notify::PeerUpdate &update);
 | 
				
			||||||
 | 
						void notifyImageLoaded();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void refreshCallback() {
 | 
				
			||||||
 | 
							update();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void processPeerPhoto();
 | 
				
			||||||
 | 
						void processNewPeerPhoto();
 | 
				
			||||||
 | 
						void startNewPhotoShowing();
 | 
				
			||||||
 | 
						QPixmap prepareUserpicPixmap() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool _notShownYet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PeerData *_peer;
 | 
				
			||||||
 | 
						bool _waiting = false;
 | 
				
			||||||
 | 
						QPixmap _userpic, _oldUserpic;
 | 
				
			||||||
 | 
						FloatAnimation _a_appearance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Profile
 | 
				
			||||||
| 
						 | 
					@ -130,6 +130,7 @@ void Widget::showAnimatedHook() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Widget::showFinishedHook() {
 | 
					void Widget::showFinishedHook() {
 | 
				
			||||||
	_fixedBar->setAnimatingMode(false);
 | 
						_fixedBar->setAnimatingMode(false);
 | 
				
			||||||
 | 
						_inner->showFinished();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Profile
 | 
					} // namespace Profile
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -160,8 +160,8 @@ QAbstractNativeEventFilter *psNativeEventFilter();
 | 
				
			||||||
void psNewVersion();
 | 
					void psNewVersion();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void psUpdateOverlayed(QWidget *widget);
 | 
					void psUpdateOverlayed(QWidget *widget);
 | 
				
			||||||
inline QString psConvertFileUrl(const QString &url) {
 | 
					inline QString psConvertFileUrl(const QUrl &url) {
 | 
				
			||||||
	return url;
 | 
						return url.toLocalFile();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
inline QByteArray psDownloadPathBookmark(const QString &path) {
 | 
					inline QByteArray psDownloadPathBookmark(const QString &path) {
 | 
				
			||||||
	return QByteArray();
 | 
						return QByteArray();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -898,8 +898,12 @@ void psSendToMenu(bool send, bool silent) {
 | 
				
			||||||
void psUpdateOverlayed(QWidget *widget) {
 | 
					void psUpdateOverlayed(QWidget *widget) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QString psConvertFileUrl(const QString &url) {
 | 
					QString psConvertFileUrl(const QUrl &url) {
 | 
				
			||||||
	return objc_convertFileUrl(url);
 | 
						auto urlString = url.toLocalFile();
 | 
				
			||||||
 | 
						if (urlString.startsWith(qsl("/.file/id="))) {
 | 
				
			||||||
 | 
							return objc_convertFileUrl(urlString);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return urlString;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void psDownloadPathEnableAccess() {
 | 
					void psDownloadPathEnableAccess() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,7 +187,7 @@ QAbstractNativeEventFilter *psNativeEventFilter();
 | 
				
			||||||
void psNewVersion();
 | 
					void psNewVersion();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void psUpdateOverlayed(QWidget *widget);
 | 
					void psUpdateOverlayed(QWidget *widget);
 | 
				
			||||||
QString psConvertFileUrl(const QString &url);
 | 
					QString psConvertFileUrl(const QUrl &url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void psDownloadPathEnableAccess();
 | 
					void psDownloadPathEnableAccess();
 | 
				
			||||||
QByteArray psDownloadPathBookmark(const QString &path);
 | 
					QByteArray psDownloadPathBookmark(const QString &path);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -164,8 +164,8 @@ QAbstractNativeEventFilter *psNativeEventFilter();
 | 
				
			||||||
void psNewVersion();
 | 
					void psNewVersion();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void psUpdateOverlayed(TWidget *widget);
 | 
					void psUpdateOverlayed(TWidget *widget);
 | 
				
			||||||
inline QString psConvertFileUrl(const QString &url) {
 | 
					inline QString psConvertFileUrl(const QUrl &url) {
 | 
				
			||||||
	return url;
 | 
						return url.toLocalFile();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
inline QByteArray psDownloadPathBookmark(const QString &path) {
 | 
					inline QByteArray psDownloadPathBookmark(const QString &path) {
 | 
				
			||||||
	return QByteArray();
 | 
						return QByteArray();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,8 +161,8 @@ QAbstractNativeEventFilter *psNativeEventFilter();
 | 
				
			||||||
void psNewVersion();
 | 
					void psNewVersion();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void psUpdateOverlayed(TWidget *widget);
 | 
					void psUpdateOverlayed(TWidget *widget);
 | 
				
			||||||
inline QString psConvertFileUrl(const QString &url) {
 | 
					inline QString psConvertFileUrl(const QUrl &url) {
 | 
				
			||||||
	return url;
 | 
						return url.toLocalFile();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
inline QByteArray psDownloadPathBookmark(const QString &path) {
 | 
					inline QByteArray psDownloadPathBookmark(const QString &path) {
 | 
				
			||||||
	return QByteArray();
 | 
						return QByteArray();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -362,7 +362,6 @@ AnimationCallbacks animation(Param param, Type *obj, typename AnimationCallbacks
 | 
				
			||||||
template <typename AnimType>
 | 
					template <typename AnimType>
 | 
				
			||||||
class SimpleAnimation {
 | 
					class SimpleAnimation {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					 | 
				
			||||||
	using Callback = Function<void>;
 | 
						using Callback = Function<void>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SimpleAnimation() {
 | 
						SimpleAnimation() {
 | 
				
			||||||
| 
						 | 
					@ -464,7 +463,16 @@ using FloatAnimation = SimpleAnimation<anim::fvalue>;
 | 
				
			||||||
using IntAnimation = SimpleAnimation<anim::ivalue>;
 | 
					using IntAnimation = SimpleAnimation<anim::ivalue>;
 | 
				
			||||||
using ColorAnimation = SimpleAnimation<anim::cvalue>;
 | 
					using ColorAnimation = SimpleAnimation<anim::cvalue>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define EnsureAnimation(animation, from, callback) if ((animation).isNull()) { (animation).setup((from), (callback)); }
 | 
					
 | 
				
			||||||
 | 
					// Macro allows us to lazily create updateCallback.
 | 
				
			||||||
 | 
					#define ENSURE_ANIMATION(animation, updateCallback, from) \
 | 
				
			||||||
 | 
					if ((animation).isNull()) { \
 | 
				
			||||||
 | 
						(animation).setup((from), (updateCallback)); \
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define START_ANIMATION(animation, updateCallback, from, to, duration, transition) \
 | 
				
			||||||
 | 
					ENSURE_ANIMATION(animation, updateCallback, from); \
 | 
				
			||||||
 | 
					(animation).start((to), (duration), (transition))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClipReader;
 | 
					class ClipReader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -335,10 +335,10 @@ void EmojiButton::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EmojiButton::setLoading(bool loading) {
 | 
					void EmojiButton::setLoading(bool loading) {
 | 
				
			||||||
	if (_loading != loading) {
 | 
						if (_loading != loading) {
 | 
				
			||||||
		EnsureAnimation(a_loading, _loading ? 1. : 0., func(this, &EmojiButton::updateCallback));
 | 
					 | 
				
			||||||
		a_loading.start(loading ? 1. : 0., st::emojiCircleDuration);
 | 
					 | 
				
			||||||
		_loading = loading;
 | 
							_loading = loading;
 | 
				
			||||||
		if (_loading) {
 | 
							auto from = loading ? 0. : 1., to = loading ? 1. : 0.;
 | 
				
			||||||
 | 
							START_ANIMATION(a_loading, func(this, &EmojiButton::updateCallback), from, to, st::emojiCircleDuration, anim::linear);
 | 
				
			||||||
 | 
							if (loading) {
 | 
				
			||||||
			_a_loading.start();
 | 
								_a_loading.start();
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			_a_loading.stop();
 | 
								_a_loading.stop();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1215,9 +1215,11 @@
 | 
				
			||||||
    <ClCompile Include="SourceFiles\profilewidget.cpp" />
 | 
					    <ClCompile Include="SourceFiles\profilewidget.cpp" />
 | 
				
			||||||
    <ClCompile Include="SourceFiles\profile\profile_block_widget.cpp" />
 | 
					    <ClCompile Include="SourceFiles\profile\profile_block_widget.cpp" />
 | 
				
			||||||
    <ClCompile Include="SourceFiles\profile\profile_cover.cpp" />
 | 
					    <ClCompile Include="SourceFiles\profile\profile_cover.cpp" />
 | 
				
			||||||
 | 
					    <ClCompile Include="SourceFiles\profile\profile_cover_drop_area.cpp" />
 | 
				
			||||||
    <ClCompile Include="SourceFiles\profile\profile_fixed_bar.cpp" />
 | 
					    <ClCompile Include="SourceFiles\profile\profile_fixed_bar.cpp" />
 | 
				
			||||||
    <ClCompile Include="SourceFiles\profile\profile_inner_widget.cpp" />
 | 
					    <ClCompile Include="SourceFiles\profile\profile_inner_widget.cpp" />
 | 
				
			||||||
    <ClCompile Include="SourceFiles\profile\profile_section_memento.cpp" />
 | 
					    <ClCompile Include="SourceFiles\profile\profile_section_memento.cpp" />
 | 
				
			||||||
 | 
					    <ClCompile Include="SourceFiles\profile\profile_userpic_button.cpp" />
 | 
				
			||||||
    <ClCompile Include="SourceFiles\profile\profile_widget.cpp" />
 | 
					    <ClCompile Include="SourceFiles\profile\profile_widget.cpp" />
 | 
				
			||||||
    <ClCompile Include="SourceFiles\pspecific_linux.cpp">
 | 
					    <ClCompile Include="SourceFiles\pspecific_linux.cpp">
 | 
				
			||||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
					      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
				
			||||||
| 
						 | 
					@ -1560,7 +1562,9 @@
 | 
				
			||||||
      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
 | 
					      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
 | 
				
			||||||
      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_block_widget.h"  -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include"</Command>
 | 
					      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_block_widget.h"  -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include"</Command>
 | 
				
			||||||
    </CustomBuild>
 | 
					    </CustomBuild>
 | 
				
			||||||
 | 
					    <ClInclude Include="SourceFiles\profile\profile_cover_drop_area.h" />
 | 
				
			||||||
    <ClInclude Include="SourceFiles\profile\profile_section_memento.h" />
 | 
					    <ClInclude Include="SourceFiles\profile\profile_section_memento.h" />
 | 
				
			||||||
 | 
					    <ClInclude Include="SourceFiles\profile\profile_userpic_button.h" />
 | 
				
			||||||
    <ClInclude Include="SourceFiles\serialize\serialize_common.h" />
 | 
					    <ClInclude Include="SourceFiles\serialize\serialize_common.h" />
 | 
				
			||||||
    <ClInclude Include="SourceFiles\serialize\serialize_document.h" />
 | 
					    <ClInclude Include="SourceFiles\serialize\serialize_document.h" />
 | 
				
			||||||
    <ClInclude Include="SourceFiles\shortcuts.h" />
 | 
					    <ClInclude Include="SourceFiles\shortcuts.h" />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1209,6 +1209,12 @@
 | 
				
			||||||
    <ClCompile Include="SourceFiles\observer_peer.cpp">
 | 
					    <ClCompile Include="SourceFiles\observer_peer.cpp">
 | 
				
			||||||
      <Filter>SourceFiles</Filter>
 | 
					      <Filter>SourceFiles</Filter>
 | 
				
			||||||
    </ClCompile>
 | 
					    </ClCompile>
 | 
				
			||||||
 | 
					    <ClCompile Include="SourceFiles\profile\profile_cover_drop_area.cpp">
 | 
				
			||||||
 | 
					      <Filter>SourceFiles\profile</Filter>
 | 
				
			||||||
 | 
					    </ClCompile>
 | 
				
			||||||
 | 
					    <ClCompile Include="SourceFiles\profile\profile_userpic_button.cpp">
 | 
				
			||||||
 | 
					      <Filter>SourceFiles\profile</Filter>
 | 
				
			||||||
 | 
					    </ClCompile>
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <ClInclude Include="SourceFiles\stdafx.h">
 | 
					    <ClInclude Include="SourceFiles\stdafx.h">
 | 
				
			||||||
| 
						 | 
					@ -1406,6 +1412,12 @@
 | 
				
			||||||
    <ClInclude Include="SourceFiles\observer_peer.h">
 | 
					    <ClInclude Include="SourceFiles\observer_peer.h">
 | 
				
			||||||
      <Filter>SourceFiles</Filter>
 | 
					      <Filter>SourceFiles</Filter>
 | 
				
			||||||
    </ClInclude>
 | 
					    </ClInclude>
 | 
				
			||||||
 | 
					    <ClInclude Include="SourceFiles\profile\profile_cover_drop_area.h">
 | 
				
			||||||
 | 
					      <Filter>SourceFiles\profile</Filter>
 | 
				
			||||||
 | 
					    </ClInclude>
 | 
				
			||||||
 | 
					    <ClInclude Include="SourceFiles\profile\profile_userpic_button.h">
 | 
				
			||||||
 | 
					      <Filter>SourceFiles\profile</Filter>
 | 
				
			||||||
 | 
					    </ClInclude>
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <CustomBuild Include="SourceFiles\application.h">
 | 
					    <CustomBuild Include="SourceFiles\application.h">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue