mirror of https://github.com/procxx/kepka.git
				
				
				
			Replace NewAvatarButton with UserpicButton.
This new control should also replace PeerAvatarButton and Profile::UserpicButton and deliver all the best of those three.
This commit is contained in:
		
							parent
							
								
									3deea14559
								
							
						
					
					
						commit
						3d37ac9235
					
				| 
						 | 
					@ -616,6 +616,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 | 
				
			||||||
"lng_info_channel_title" = "Channel Info";
 | 
					"lng_info_channel_title" = "Channel Info";
 | 
				
			||||||
"lng_profile_enable_notifications" = "Notifications";
 | 
					"lng_profile_enable_notifications" = "Notifications";
 | 
				
			||||||
"lng_profile_send_message" = "Send Message";
 | 
					"lng_profile_send_message" = "Send Message";
 | 
				
			||||||
 | 
					"lng_profile_edit_group_name" = "Edit group name";
 | 
				
			||||||
"lng_info_add_as_contact" = "Add as contact";
 | 
					"lng_info_add_as_contact" = "Add as contact";
 | 
				
			||||||
"lng_profile_shared_media" = "Shared media";
 | 
					"lng_profile_shared_media" = "Shared media";
 | 
				
			||||||
"lng_media_type_photos" = "Photos";
 | 
					"lng_media_type_photos" = "Photos";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,6 +116,10 @@ public:
 | 
				
			||||||
		finishPrepare();
 | 
							finishPrepare();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Window::Controller *controller() {
 | 
				
			||||||
 | 
							return getDelegate()->controller();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public slots:
 | 
					public slots:
 | 
				
			||||||
	void onScrollToY(int top, int bottom = -1);
 | 
						void onScrollToY(int top, int bottom = -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,10 +128,6 @@ public slots:
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	virtual void prepare() = 0;
 | 
						virtual void prepare() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Window::Controller *controller() {
 | 
					 | 
				
			||||||
		return getDelegate()->controller();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void setLayerType(bool layerType) {
 | 
						void setLayerType(bool layerType) {
 | 
				
			||||||
		getDelegate()->setLayerType(layerType);
 | 
							getDelegate()->setLayerType(layerType);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -307,14 +307,25 @@ void AddContactBox::updateButtons() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GroupInfoBox::GroupInfoBox(QWidget*, CreatingGroupType creating, bool fromTypeChoose)
 | 
					GroupInfoBox::GroupInfoBox(QWidget*, CreatingGroupType creating, bool fromTypeChoose)
 | 
				
			||||||
: _creating(creating)
 | 
					: _creating(creating)
 | 
				
			||||||
, _fromTypeChoose(fromTypeChoose)
 | 
					, _fromTypeChoose(fromTypeChoose) {
 | 
				
			||||||
, _photo(this, st::newGroupPhotoSize, st::newGroupPhotoIconPosition)
 | 
					 | 
				
			||||||
, _title(this, st::defaultInputField, langFactory(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name)) {
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GroupInfoBox::prepare() {
 | 
					void GroupInfoBox::prepare() {
 | 
				
			||||||
	setMouseTracking(true);
 | 
						setMouseTracking(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_photo.create(
 | 
				
			||||||
 | 
							this,
 | 
				
			||||||
 | 
							(_creating == CreatingGroupChannel)
 | 
				
			||||||
 | 
								? peerFromChannel(0)
 | 
				
			||||||
 | 
								: peerFromChat(0),
 | 
				
			||||||
 | 
							Ui::UserpicButton::Role::ChangePhoto,
 | 
				
			||||||
 | 
							st::defaultUserpicButton);
 | 
				
			||||||
 | 
						_title.create(
 | 
				
			||||||
 | 
							this,
 | 
				
			||||||
 | 
							st::defaultInputField,
 | 
				
			||||||
 | 
							langFactory(_creating == CreatingGroupChannel
 | 
				
			||||||
 | 
								? lng_dlg_new_channel_name
 | 
				
			||||||
 | 
								: lng_dlg_new_group_name));
 | 
				
			||||||
	_title->setMaxLength(kMaxGroupChannelTitle);
 | 
						_title->setMaxLength(kMaxGroupChannelTitle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (_creating == CreatingGroupChannel) {
 | 
						if (_creating == CreatingGroupChannel) {
 | 
				
			||||||
| 
						 | 
					@ -332,41 +343,9 @@ void GroupInfoBox::prepare() {
 | 
				
			||||||
	addButton(langFactory(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), [this] { onNext(); });
 | 
						addButton(langFactory(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), [this] { onNext(); });
 | 
				
			||||||
	addButton(langFactory(_fromTypeChoose ? lng_create_group_back : lng_cancel), [this] { closeBox(); });
 | 
						addButton(langFactory(_fromTypeChoose ? lng_create_group_back : lng_cancel), [this] { closeBox(); });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setupPhotoButton();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	updateMaxHeight();
 | 
						updateMaxHeight();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GroupInfoBox::setupPhotoButton() {
 | 
					 | 
				
			||||||
	_photo->setClickedCallback(App::LambdaDelayed(st::defaultActiveButton.ripple.hideDuration, this, [this] {
 | 
					 | 
				
			||||||
		auto imgExtensions = cImgExtensions();
 | 
					 | 
				
			||||||
		auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + FileDialog::AllFilesFilter();
 | 
					 | 
				
			||||||
		FileDialog::GetOpenPath(lang(lng_choose_image), filter, base::lambda_guarded(this, [this](const FileDialog::OpenResult &result) {
 | 
					 | 
				
			||||||
			if (result.remoteContent.isEmpty() && result.paths.isEmpty()) {
 | 
					 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			QImage img;
 | 
					 | 
				
			||||||
			if (!result.remoteContent.isEmpty()) {
 | 
					 | 
				
			||||||
				img = App::readImage(result.remoteContent);
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				img = App::readImage(result.paths.front());
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) {
 | 
					 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			auto box = Ui::show(
 | 
					 | 
				
			||||||
				Box<PhotoCropBox>(
 | 
					 | 
				
			||||||
					img,
 | 
					 | 
				
			||||||
					(_creating == CreatingGroupChannel)
 | 
					 | 
				
			||||||
						? peerFromChannel(0)
 | 
					 | 
				
			||||||
						: peerFromChat(0)),
 | 
					 | 
				
			||||||
				LayerOption::KeepOther);
 | 
					 | 
				
			||||||
			connect(box, SIGNAL(ready(const QImage&)), this, SLOT(onPhotoReady(const QImage&)));
 | 
					 | 
				
			||||||
		}));
 | 
					 | 
				
			||||||
	}));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void GroupInfoBox::setInnerFocus() {
 | 
					void GroupInfoBox::setInnerFocus() {
 | 
				
			||||||
	_title->setFocusFast();
 | 
						_title->setFocusFast();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -376,12 +355,19 @@ void GroupInfoBox::resizeEvent(QResizeEvent *e) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_photo->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top());
 | 
						_photo->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto nameLeft = st::newGroupPhotoSize + st::newGroupNamePosition.x();
 | 
						auto nameLeft = st::defaultUserpicButton.size.width()
 | 
				
			||||||
 | 
							+ st::newGroupNamePosition.x();
 | 
				
			||||||
	_title->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right() - nameLeft, _title->height());
 | 
						_title->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right() - nameLeft, _title->height());
 | 
				
			||||||
	_title->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft, st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y());
 | 
						_title->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft, st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y());
 | 
				
			||||||
	if (_description) {
 | 
						if (_description) {
 | 
				
			||||||
		_description->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _description->height());
 | 
							_description->resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _description->height());
 | 
				
			||||||
		_description->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + st::newGroupDescriptionPadding.top());
 | 
							auto descriptionLeft = st::boxPadding.left()
 | 
				
			||||||
 | 
								+ st::newGroupInfoPadding.left();
 | 
				
			||||||
 | 
							auto descriptionTop = st::boxPadding.top()
 | 
				
			||||||
 | 
								+ st::newGroupInfoPadding.top()
 | 
				
			||||||
 | 
								+ st::defaultUserpicButton.size.height()
 | 
				
			||||||
 | 
								+ st::newGroupDescriptionPadding.top();
 | 
				
			||||||
 | 
							_description->moveToLeft(descriptionLeft, descriptionTop);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -433,8 +419,11 @@ void GroupInfoBox::createGroup(not_null<PeerListBox*> selectUsersBox, const QStr
 | 
				
			||||||
				return App::chat(chats->front().c_chat().vid.v);
 | 
									return App::chat(chats->front().c_chat().vid.v);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			| [this](not_null<ChatData*> chat) {
 | 
								| [this](not_null<ChatData*> chat) {
 | 
				
			||||||
				if (!_photoImage.isNull()) {
 | 
									auto image = _photo->takeResultImage();
 | 
				
			||||||
					Messenger::Instance().uploadProfilePhoto(_photoImage, chat->id);
 | 
									if (!image.isNull()) {
 | 
				
			||||||
 | 
										Messenger::Instance().uploadProfilePhoto(
 | 
				
			||||||
 | 
											std::move(image),
 | 
				
			||||||
 | 
											chat->id);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				Ui::showPeerHistory(chat, ShowAtUnreadMsgId);
 | 
									Ui::showPeerHistory(chat, ShowAtUnreadMsgId);
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
| 
						 | 
					@ -522,9 +511,10 @@ void GroupInfoBox::createChannel(const QString &title, const QString &descriptio
 | 
				
			||||||
				return App::channel(chats->front().c_channel().vid.v);
 | 
									return App::channel(chats->front().c_channel().vid.v);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			| [this](not_null<ChannelData*> channel) {
 | 
								| [this](not_null<ChannelData*> channel) {
 | 
				
			||||||
				if (!_photoImage.isNull()) {
 | 
									auto image = _photo->takeResultImage();
 | 
				
			||||||
 | 
									if (!image.isNull()) {
 | 
				
			||||||
					Messenger::Instance().uploadProfilePhoto(
 | 
										Messenger::Instance().uploadProfilePhoto(
 | 
				
			||||||
						_photoImage,
 | 
											std::move(image),
 | 
				
			||||||
						channel->id);
 | 
											channel->id);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				_createdChannel = channel;
 | 
									_createdChannel = channel;
 | 
				
			||||||
| 
						 | 
					@ -562,18 +552,19 @@ void GroupInfoBox::onDescriptionResized() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GroupInfoBox::updateMaxHeight() {
 | 
					void GroupInfoBox::updateMaxHeight() {
 | 
				
			||||||
	auto newHeight = st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + st::boxPadding.bottom() + st::newGroupInfoPadding.bottom();
 | 
						auto newHeight = st::boxPadding.top()
 | 
				
			||||||
 | 
							+ st::newGroupInfoPadding.top()
 | 
				
			||||||
 | 
							+ st::defaultUserpicButton.size.height()
 | 
				
			||||||
 | 
							+ st::boxPadding.bottom()
 | 
				
			||||||
 | 
							+ st::newGroupInfoPadding.bottom();
 | 
				
			||||||
	if (_description) {
 | 
						if (_description) {
 | 
				
			||||||
		newHeight += st::newGroupDescriptionPadding.top() + _description->height() + st::newGroupDescriptionPadding.bottom();
 | 
							newHeight += st::newGroupDescriptionPadding.top()
 | 
				
			||||||
 | 
								+ _description->height()
 | 
				
			||||||
 | 
								+ st::newGroupDescriptionPadding.bottom();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	setDimensions(st::boxWideWidth, newHeight);
 | 
						setDimensions(st::boxWideWidth, newHeight);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GroupInfoBox::onPhotoReady(const QImage &img) {
 | 
					 | 
				
			||||||
	_photoImage = img;
 | 
					 | 
				
			||||||
	_photo->setImage(_photoImage);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SetupChannelBox::SetupChannelBox(QWidget*, ChannelData *channel, bool existing)
 | 
					SetupChannelBox::SetupChannelBox(QWidget*, ChannelData *channel, bool existing)
 | 
				
			||||||
: _channel(channel)
 | 
					: _channel(channel)
 | 
				
			||||||
, _existing(existing)
 | 
					, _existing(existing)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@ class RadioenumGroup;
 | 
				
			||||||
template <typename Enum>
 | 
					template <typename Enum>
 | 
				
			||||||
class Radioenum;
 | 
					class Radioenum;
 | 
				
			||||||
class LinkButton;
 | 
					class LinkButton;
 | 
				
			||||||
class NewAvatarButton;
 | 
					class UserpicButton;
 | 
				
			||||||
} // namespace Ui
 | 
					} // namespace Ui
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class PeerFloodType {
 | 
					enum class PeerFloodType {
 | 
				
			||||||
| 
						 | 
					@ -105,8 +105,6 @@ protected:
 | 
				
			||||||
	void resizeEvent(QResizeEvent *e) override;
 | 
						void resizeEvent(QResizeEvent *e) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
	void onPhotoReady(const QImage &img);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void onNext();
 | 
						void onNext();
 | 
				
			||||||
	void onNameSubmit();
 | 
						void onNameSubmit();
 | 
				
			||||||
	void onDescriptionResized();
 | 
						void onDescriptionResized();
 | 
				
			||||||
| 
						 | 
					@ -115,7 +113,6 @@ private slots:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void setupPhotoButton();
 | 
					 | 
				
			||||||
	void createChannel(const QString &title, const QString &description);
 | 
						void createChannel(const QString &title, const QString &description);
 | 
				
			||||||
	void createGroup(not_null<PeerListBox*> selectUsersBox, const QString &title, const std::vector<not_null<PeerData*>> &users);
 | 
						void createGroup(not_null<PeerListBox*> selectUsersBox, const QString &title, const std::vector<not_null<PeerData*>> &users);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,12 +122,10 @@ private:
 | 
				
			||||||
	CreatingGroupType _creating;
 | 
						CreatingGroupType _creating;
 | 
				
			||||||
	bool _fromTypeChoose = false;
 | 
						bool _fromTypeChoose = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	object_ptr<Ui::NewAvatarButton> _photo;
 | 
						object_ptr<Ui::UserpicButton> _photo = { nullptr };
 | 
				
			||||||
	object_ptr<Ui::InputField> _title;
 | 
						object_ptr<Ui::InputField> _title = { nullptr };
 | 
				
			||||||
	object_ptr<Ui::InputArea> _description = { nullptr };
 | 
						object_ptr<Ui::InputArea> _description = { nullptr };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QImage _photoImage;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// group / channel creation
 | 
						// group / channel creation
 | 
				
			||||||
	mtpRequestId _creationRequestId = 0;
 | 
						mtpRequestId _creationRequestId = 0;
 | 
				
			||||||
	ChannelData *_createdChannel = nullptr;
 | 
						ChannelData *_createdChannel = nullptr;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -457,11 +457,6 @@ newGroupLinkPadding: margins(4px, 27px, 4px, 21px);
 | 
				
			||||||
newGroupLinkTop: 3px;
 | 
					newGroupLinkTop: 3px;
 | 
				
			||||||
newGroupLinkFont: font(16px);
 | 
					newGroupLinkFont: font(16px);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
newGroupPhotoSize: 76px;
 | 
					 | 
				
			||||||
newGroupPhotoIcon: icon {{ "new_chat_photo", activeButtonFg }};
 | 
					 | 
				
			||||||
newGroupPhotoIconPosition: point(23px, 25px);
 | 
					 | 
				
			||||||
newGroupPhotoDuration: 150;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
newGroupNamePosition: point(27px, 5px);
 | 
					newGroupNamePosition: point(27px, 5px);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
newGroupDescriptionPadding: margins(0px, 13px, 0px, 4px);
 | 
					newGroupDescriptionPadding: margins(0px, 13px, 0px, 4px);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,8 +36,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 | 
				
			||||||
#include "boxes/add_contact_box.h"
 | 
					#include "boxes/add_contact_box.h"
 | 
				
			||||||
#include "mtproto/sender.h"
 | 
					#include "mtproto/sender.h"
 | 
				
			||||||
#include "lang/lang_keys.h"
 | 
					#include "lang/lang_keys.h"
 | 
				
			||||||
#include "core/file_utilities.h"
 | 
					 | 
				
			||||||
#include "mainwidget.h"
 | 
					#include "mainwidget.h"
 | 
				
			||||||
 | 
					#include "messenger.h"
 | 
				
			||||||
#include "apiwrap.h"
 | 
					#include "apiwrap.h"
 | 
				
			||||||
#include "application.h"
 | 
					#include "application.h"
 | 
				
			||||||
#include "auth_session.h"
 | 
					#include "auth_session.h"
 | 
				
			||||||
| 
						 | 
					@ -77,7 +77,7 @@ private:
 | 
				
			||||||
	struct Controls {
 | 
						struct Controls {
 | 
				
			||||||
		Ui::InputField *title = nullptr;
 | 
							Ui::InputField *title = nullptr;
 | 
				
			||||||
		Ui::InputArea *description = nullptr;
 | 
							Ui::InputArea *description = nullptr;
 | 
				
			||||||
		Ui::NewAvatarButton *photo = nullptr;
 | 
							Ui::UserpicButton *photo = nullptr;
 | 
				
			||||||
		rpl::lifetime initialPhotoImageWaiting;
 | 
							rpl::lifetime initialPhotoImageWaiting;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		std::shared_ptr<Ui::RadioenumGroup<Privacy>> privacy;
 | 
							std::shared_ptr<Ui::RadioenumGroup<Privacy>> privacy;
 | 
				
			||||||
| 
						 | 
					@ -118,11 +118,6 @@ private:
 | 
				
			||||||
	void submitTitle();
 | 
						void submitTitle();
 | 
				
			||||||
	void submitDescription();
 | 
						void submitDescription();
 | 
				
			||||||
	void deleteWithConfirmation();
 | 
						void deleteWithConfirmation();
 | 
				
			||||||
	void choosePhotoDelayed();
 | 
					 | 
				
			||||||
	void choosePhoto();
 | 
					 | 
				
			||||||
	void suggestPhotoFile(
 | 
					 | 
				
			||||||
		const FileDialog::OpenResult &result);
 | 
					 | 
				
			||||||
	void suggestPhoto(const QImage &image);
 | 
					 | 
				
			||||||
	void privacyChanged(Privacy value);
 | 
						void privacyChanged(Privacy value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void checkUsernameAvailability();
 | 
						void checkUsernameAvailability();
 | 
				
			||||||
| 
						 | 
					@ -155,6 +150,7 @@ private:
 | 
				
			||||||
	void saveDescription();
 | 
						void saveDescription();
 | 
				
			||||||
	void saveInvites();
 | 
						void saveInvites();
 | 
				
			||||||
	void saveSignatures();
 | 
						void saveSignatures();
 | 
				
			||||||
 | 
						void savePhoto();
 | 
				
			||||||
	void pushSaveStage(base::lambda_once<void()> &&lambda);
 | 
						void pushSaveStage(base::lambda_once<void()> &&lambda);
 | 
				
			||||||
	void continueSave();
 | 
						void continueSave();
 | 
				
			||||||
	void cancelSave();
 | 
						void cancelSave();
 | 
				
			||||||
| 
						 | 
					@ -245,7 +241,7 @@ object_ptr<Ui::RpWidget> Controller::createPhotoAndTitleEdit() {
 | 
				
			||||||
	container->widthValue()
 | 
						container->widthValue()
 | 
				
			||||||
		| rpl::start_with_next([titleEdit](int width) {
 | 
							| rpl::start_with_next([titleEdit](int width) {
 | 
				
			||||||
			auto left = st::editPeerPhotoMargins.left()
 | 
								auto left = st::editPeerPhotoMargins.left()
 | 
				
			||||||
				+ st::editPeerPhotoSize;
 | 
									+ st::defaultUserpicButton.size.width();
 | 
				
			||||||
			titleEdit->resizeToWidth(width - left);
 | 
								titleEdit->resizeToWidth(width - left);
 | 
				
			||||||
			titleEdit->moveToLeft(left, 0, width);
 | 
								titleEdit->moveToLeft(left, 0, width);
 | 
				
			||||||
		}, titleEdit->lifetime());
 | 
							}, titleEdit->lifetime());
 | 
				
			||||||
| 
						 | 
					@ -256,16 +252,17 @@ object_ptr<Ui::RpWidget> Controller::createPhotoAndTitleEdit() {
 | 
				
			||||||
object_ptr<Ui::RpWidget> Controller::createPhotoEdit() {
 | 
					object_ptr<Ui::RpWidget> Controller::createPhotoEdit() {
 | 
				
			||||||
	Expects(_wrap != nullptr);
 | 
						Expects(_wrap != nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	using PhotoWrap = Ui::PaddingWrap<Ui::NewAvatarButton>;
 | 
						using PhotoWrap = Ui::PaddingWrap<Ui::UserpicButton>;
 | 
				
			||||||
	auto photoWrap = object_ptr<PhotoWrap>(
 | 
						auto photoWrap = object_ptr<PhotoWrap>(
 | 
				
			||||||
		_wrap,
 | 
							_wrap,
 | 
				
			||||||
		object_ptr<Ui::NewAvatarButton>(
 | 
							object_ptr<Ui::UserpicButton>(
 | 
				
			||||||
			_wrap,
 | 
								_wrap,
 | 
				
			||||||
			st::editPeerPhotoSize,
 | 
								_box->controller(),
 | 
				
			||||||
			st::editPeerPhotoIconPosition),
 | 
								_channel,
 | 
				
			||||||
 | 
								Ui::UserpicButton::Role::ChangePhoto,
 | 
				
			||||||
 | 
								st::defaultUserpicButton),
 | 
				
			||||||
		st::editPeerPhotoMargins);
 | 
							st::editPeerPhotoMargins);
 | 
				
			||||||
	_controls.photo = photoWrap->entity();
 | 
						_controls.photo = photoWrap->entity();
 | 
				
			||||||
	_controls.photo->addClickHandler([this] { choosePhotoDelayed(); });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_controls.initialPhotoImageWaiting = base::ObservableViewer(
 | 
						_controls.initialPhotoImageWaiting = base::ObservableViewer(
 | 
				
			||||||
		Auth().downloaderTaskFinished())
 | 
							Auth().downloaderTaskFinished())
 | 
				
			||||||
| 
						 | 
					@ -278,18 +275,18 @@ object_ptr<Ui::RpWidget> Controller::createPhotoEdit() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Controller::refreshInitialPhotoImage() {
 | 
					void Controller::refreshInitialPhotoImage() {
 | 
				
			||||||
	if (auto image = _channel->currentUserpic()) {
 | 
						//if (auto image = _channel->currentUserpic()) {
 | 
				
			||||||
		image->load();
 | 
						//	image->load();
 | 
				
			||||||
		if (image->loaded()) {
 | 
						//	if (image->loaded()) {
 | 
				
			||||||
			_controls.photo->setImage(image->pixNoCache(
 | 
						//		_controls.photo->setImage(image->pixNoCache(
 | 
				
			||||||
				st::editPeerPhotoSize * cIntRetinaFactor(),
 | 
						//			st::editPeerPhotoSize * cIntRetinaFactor(),
 | 
				
			||||||
				st::editPeerPhotoSize * cIntRetinaFactor(),
 | 
						//			st::editPeerPhotoSize * cIntRetinaFactor(),
 | 
				
			||||||
				Images::Option::Smooth).toImage());
 | 
						//			Images::Option::Smooth).toImage());
 | 
				
			||||||
			_controls.initialPhotoImageWaiting.destroy();
 | 
						//		_controls.initialPhotoImageWaiting.destroy();
 | 
				
			||||||
		}
 | 
						//	}
 | 
				
			||||||
	} else {
 | 
						//} else {
 | 
				
			||||||
		_controls.initialPhotoImageWaiting.destroy();
 | 
						//	_controls.initialPhotoImageWaiting.destroy();
 | 
				
			||||||
	}
 | 
						//}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
 | 
					object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
 | 
				
			||||||
| 
						 | 
					@ -968,7 +965,7 @@ void Controller::save() {
 | 
				
			||||||
		pushSaveStage([this] { saveDescription(); });
 | 
							pushSaveStage([this] { saveDescription(); });
 | 
				
			||||||
		pushSaveStage([this] { saveInvites(); });
 | 
							pushSaveStage([this] { saveInvites(); });
 | 
				
			||||||
		pushSaveStage([this] { saveSignatures(); });
 | 
							pushSaveStage([this] { saveSignatures(); });
 | 
				
			||||||
		pushSaveStage([this] { _box->closeBox(); });
 | 
							pushSaveStage([this] { savePhoto(); });
 | 
				
			||||||
		continueSave();
 | 
							continueSave();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1122,6 +1119,18 @@ void Controller::saveSignatures() {
 | 
				
			||||||
	}).send();
 | 
						}).send();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Controller::savePhoto() {
 | 
				
			||||||
 | 
						auto image = _controls.photo
 | 
				
			||||||
 | 
							? _controls.photo->takeResultImage()
 | 
				
			||||||
 | 
							: QImage();
 | 
				
			||||||
 | 
						if (!image.isNull()) {
 | 
				
			||||||
 | 
							Messenger::Instance().uploadProfilePhoto(
 | 
				
			||||||
 | 
								std::move(image),
 | 
				
			||||||
 | 
								_channel->id);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_box->closeBox();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Controller::deleteWithConfirmation() {
 | 
					void Controller::deleteWithConfirmation() {
 | 
				
			||||||
	auto text = lang(_isGroup
 | 
						auto text = lang(_isGroup
 | 
				
			||||||
		? lng_sure_delete_group
 | 
							? lng_sure_delete_group
 | 
				
			||||||
| 
						 | 
					@ -1144,66 +1153,6 @@ void Controller::deleteWithConfirmation() {
 | 
				
			||||||
		std::move(deleteCallback)), LayerOption::KeepOther);
 | 
							std::move(deleteCallback)), LayerOption::KeepOther);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Controller::choosePhotoDelayed() {
 | 
					 | 
				
			||||||
	App::CallDelayed(
 | 
					 | 
				
			||||||
		st::defaultRippleAnimation.hideDuration,
 | 
					 | 
				
			||||||
		this,
 | 
					 | 
				
			||||||
		[this] { choosePhoto(); });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Controller::choosePhoto() {
 | 
					 | 
				
			||||||
	auto handleChosenPhoto = base::lambda_guarded(
 | 
					 | 
				
			||||||
		_controls.photo,
 | 
					 | 
				
			||||||
		[this](auto &&result) { suggestPhotoFile(result); });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto imgExtensions = cImgExtensions();
 | 
					 | 
				
			||||||
	auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + FileDialog::AllFilesFilter();
 | 
					 | 
				
			||||||
	FileDialog::GetOpenPath(
 | 
					 | 
				
			||||||
		lang(lng_choose_image),
 | 
					 | 
				
			||||||
		filter,
 | 
					 | 
				
			||||||
		std::move(handleChosenPhoto));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Controller::suggestPhotoFile(
 | 
					 | 
				
			||||||
		const FileDialog::OpenResult &result) {
 | 
					 | 
				
			||||||
	if (result.paths.isEmpty() && result.remoteContent.isEmpty()) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto image = [&] {
 | 
					 | 
				
			||||||
		if (!result.remoteContent.isEmpty()) {
 | 
					 | 
				
			||||||
			return App::readImage(result.remoteContent);
 | 
					 | 
				
			||||||
		} else if (!result.paths.isEmpty()) {
 | 
					 | 
				
			||||||
			return App::readImage(result.paths.front());
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return QImage();
 | 
					 | 
				
			||||||
	}();
 | 
					 | 
				
			||||||
	suggestPhoto(image);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Controller::suggestPhoto(const QImage &image) {
 | 
					 | 
				
			||||||
	auto badAspect = [](int a, int b) {
 | 
					 | 
				
			||||||
		return (a >= 10 * b);
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	if (image.isNull()
 | 
					 | 
				
			||||||
		|| badAspect(image.width(), image.height())
 | 
					 | 
				
			||||||
		|| badAspect(image.height(), image.width())) {
 | 
					 | 
				
			||||||
		Ui::show(Box<InformBox>(lang(lng_bad_photo)));
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto callback = [this](const QImage &cropped) {
 | 
					 | 
				
			||||||
		_controls.photo->setImage(cropped);
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	auto box = Ui::show(
 | 
					 | 
				
			||||||
		Box<PhotoCropBox>(image, _channel),
 | 
					 | 
				
			||||||
		LayerOption::KeepOther);
 | 
					 | 
				
			||||||
	QObject::connect(
 | 
					 | 
				
			||||||
		box,
 | 
					 | 
				
			||||||
		&PhotoCropBox::ready,
 | 
					 | 
				
			||||||
		base::lambda_guarded(_controls.photo, std::move(callback)));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EditPeerInfoBox::EditPeerInfoBox(
 | 
					EditPeerInfoBox::EditPeerInfoBox(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,9 +21,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 | 
				
			||||||
#include "boxes/photo_crop_box.h"
 | 
					#include "boxes/photo_crop_box.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "lang/lang_keys.h"
 | 
					#include "lang/lang_keys.h"
 | 
				
			||||||
#include "messenger.h"
 | 
					 | 
				
			||||||
#include "mainwidget.h"
 | 
					 | 
				
			||||||
#include "storage/file_upload.h"
 | 
					 | 
				
			||||||
#include "ui/widgets/buttons.h"
 | 
					#include "ui/widgets/buttons.h"
 | 
				
			||||||
#include "styles/style_boxes.h"
 | 
					#include "styles/style_boxes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +30,7 @@ PhotoCropBox::PhotoCropBox(QWidget*, const QImage &img, const PeerId &peer)
 | 
				
			||||||
	init(img, nullptr);
 | 
						init(img, nullptr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PhotoCropBox::PhotoCropBox(QWidget*, const QImage &img, PeerData *peer)
 | 
					PhotoCropBox::PhotoCropBox(QWidget*, const QImage &img, not_null<PeerData*> peer)
 | 
				
			||||||
: _img(img)
 | 
					: _img(img)
 | 
				
			||||||
, _peerId(peer->id) {
 | 
					, _peerId(peer->id) {
 | 
				
			||||||
	init(img, peer);
 | 
						init(img, peer);
 | 
				
			||||||
| 
						 | 
					@ -52,9 +49,6 @@ void PhotoCropBox::init(const QImage &img, PeerData *peer) {
 | 
				
			||||||
void PhotoCropBox::prepare() {
 | 
					void PhotoCropBox::prepare() {
 | 
				
			||||||
	addButton(langFactory(lng_settings_save), [this] { sendPhoto(); });
 | 
						addButton(langFactory(lng_settings_save), [this] { sendPhoto(); });
 | 
				
			||||||
	addButton(langFactory(lng_cancel), [this] { closeBox(); });
 | 
						addButton(langFactory(lng_cancel), [this] { closeBox(); });
 | 
				
			||||||
	if (peerToBareInt(_peerId)) {
 | 
					 | 
				
			||||||
		connect(this, SIGNAL(ready(const QImage&)), this, SLOT(onReady(const QImage&)));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
 | 
						int32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
 | 
				
			||||||
	_thumb = App::pixmapFromImageInPlace(_img.scaled(s * cIntRetinaFactor(), s * cIntRetinaFactor(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
 | 
						_thumb = App::pixmapFromImageInPlace(_img.scaled(s * cIntRetinaFactor(), s * cIntRetinaFactor(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
 | 
				
			||||||
| 
						 | 
					@ -288,10 +282,9 @@ void PhotoCropBox::sendPhoto() {
 | 
				
			||||||
		tosend = cropped.copy();
 | 
							tosend = cropped.copy();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	emit ready(tosend);
 | 
						auto guard = weak(this);
 | 
				
			||||||
	closeBox();
 | 
						_readyImages.fire(std::move(tosend));
 | 
				
			||||||
}
 | 
						if (guard) {
 | 
				
			||||||
 | 
							closeBox();
 | 
				
			||||||
void PhotoCropBox::onReady(const QImage &tosend) {
 | 
						}
 | 
				
			||||||
	Messenger::Instance().uploadProfilePhoto(tosend, _peerId);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,19 +23,15 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 | 
				
			||||||
#include "boxes/abstract_box.h"
 | 
					#include "boxes/abstract_box.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PhotoCropBox : public BoxContent {
 | 
					class PhotoCropBox : public BoxContent {
 | 
				
			||||||
	Q_OBJECT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	PhotoCropBox(QWidget*, const QImage &img, const PeerId &peer);
 | 
						PhotoCropBox(QWidget*, const QImage &img, const PeerId &peer);
 | 
				
			||||||
	PhotoCropBox(QWidget*, const QImage &img, PeerData *peer);
 | 
						PhotoCropBox(QWidget*, const QImage &img, not_null<PeerData*> peer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int32 mouseState(QPoint p);
 | 
						int32 mouseState(QPoint p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
signals:
 | 
						rpl::producer<QImage> ready() const {
 | 
				
			||||||
	void ready(const QImage &tosend);
 | 
							return _readyImages.events();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
private slots:
 | 
					 | 
				
			||||||
	void onReady(const QImage &tosend);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	void prepare() override;
 | 
						void prepare() override;
 | 
				
			||||||
| 
						 | 
					@ -58,6 +54,7 @@ private:
 | 
				
			||||||
	QImage _img;
 | 
						QImage _img;
 | 
				
			||||||
	QPixmap _thumb;
 | 
						QPixmap _thumb;
 | 
				
			||||||
	QImage _mask, _fade;
 | 
						QImage _mask, _fade;
 | 
				
			||||||
	PeerId _peerId;
 | 
						PeerId _peerId = 0;
 | 
				
			||||||
 | 
						rpl::event_stream<QImage> _readyImages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -547,8 +547,6 @@ managePeerButtonLabelPosition: point(25px, 10px);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
editPeerDeleteButtonMargins: margins(23px, 16px, 23px, 16px);
 | 
					editPeerDeleteButtonMargins: margins(23px, 16px, 23px, 16px);
 | 
				
			||||||
editPeerDeleteButton: sessionTerminateAllButton;
 | 
					editPeerDeleteButton: sessionTerminateAllButton;
 | 
				
			||||||
editPeerPhotoSize: newGroupPhotoSize;
 | 
					 | 
				
			||||||
editPeerPhotoIconPosition: newGroupPhotoIconPosition;
 | 
					 | 
				
			||||||
editPeerPhotoMargins: margins(23px, 16px, 23px, 8px);
 | 
					editPeerPhotoMargins: margins(23px, 16px, 23px, 8px);
 | 
				
			||||||
editPeerTitle: defaultInputField;
 | 
					editPeerTitle: defaultInputField;
 | 
				
			||||||
editPeerTitleMargins: margins(27px, 21px, 23px, 8px);
 | 
					editPeerTitleMargins: margins(27px, 21px, 23px, 8px);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,8 +39,6 @@ introCoverIconTop: 46px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
introSettingsSkip: 10px;
 | 
					introSettingsSkip: 10px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
introPhotoSize: 76px;
 | 
					 | 
				
			||||||
introPhotoIconPosition: point(23px, 25px);
 | 
					 | 
				
			||||||
introPhotoTop: 10px;
 | 
					introPhotoTop: 10px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
introCoverTitle: FlatLabel(defaultFlatLabel) {
 | 
					introCoverTitle: FlatLabel(defaultFlatLabel) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 | 
				
			||||||
namespace Intro {
 | 
					namespace Intro {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SignupWidget::SignupWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
 | 
					SignupWidget::SignupWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
 | 
				
			||||||
, _photo(this, st::introPhotoSize, st::introPhotoIconPosition)
 | 
					, _photo(
 | 
				
			||||||
 | 
						this,
 | 
				
			||||||
 | 
						peerFromUser(0),
 | 
				
			||||||
 | 
						Ui::UserpicButton::Role::ChangePhoto,
 | 
				
			||||||
 | 
						st::defaultUserpicButton)
 | 
				
			||||||
, _first(this, st::introName, langFactory(lng_signup_firstname))
 | 
					, _first(this, st::introName, langFactory(lng_signup_firstname))
 | 
				
			||||||
, _last(this, st::introName, langFactory(lng_signup_lastname))
 | 
					, _last(this, st::introName, langFactory(lng_signup_lastname))
 | 
				
			||||||
, _invertOrder(langFirstNameGoesSecond())
 | 
					, _invertOrder(langFirstNameGoesSecond())
 | 
				
			||||||
| 
						 | 
					@ -49,8 +53,6 @@ SignupWidget::SignupWidget(QWidget *parent, Widget::Data *data) : Step(parent, d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
 | 
						connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setupPhotoButton();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	setErrorCentered(true);
 | 
						setErrorCentered(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setTitleText(langFactory(lng_signup_title));
 | 
						setTitleText(langFactory(lng_signup_title));
 | 
				
			||||||
| 
						 | 
					@ -68,32 +70,6 @@ void SignupWidget::refreshLang() {
 | 
				
			||||||
	updateControlsGeometry();
 | 
						updateControlsGeometry();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SignupWidget::setupPhotoButton() {
 | 
					 | 
				
			||||||
	_photo->setClickedCallback(App::LambdaDelayed(st::defaultActiveButton.ripple.hideDuration, this, [this] {
 | 
					 | 
				
			||||||
		auto imgExtensions = cImgExtensions();
 | 
					 | 
				
			||||||
		auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + FileDialog::AllFilesFilter();
 | 
					 | 
				
			||||||
		FileDialog::GetOpenPath(lang(lng_choose_image), filter, base::lambda_guarded(this, [this](const FileDialog::OpenResult &result) {
 | 
					 | 
				
			||||||
			if (result.remoteContent.isEmpty() && result.paths.isEmpty()) {
 | 
					 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			QImage img;
 | 
					 | 
				
			||||||
			if (!result.remoteContent.isEmpty()) {
 | 
					 | 
				
			||||||
				img = App::readImage(result.remoteContent);
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				img = App::readImage(result.paths.front());
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) {
 | 
					 | 
				
			||||||
				showError(langFactory(lng_bad_photo));
 | 
					 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			auto box = Ui::show(Box<PhotoCropBox>(img, PeerId(0)));
 | 
					 | 
				
			||||||
			connect(box, SIGNAL(ready(const QImage&)), this, SLOT(onPhotoReady(const QImage&)));
 | 
					 | 
				
			||||||
		}));
 | 
					 | 
				
			||||||
	}));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SignupWidget::resizeEvent(QResizeEvent *e) {
 | 
					void SignupWidget::resizeEvent(QResizeEvent *e) {
 | 
				
			||||||
	Step::resizeEvent(e);
 | 
						Step::resizeEvent(e);
 | 
				
			||||||
	updateControlsGeometry();
 | 
						updateControlsGeometry();
 | 
				
			||||||
| 
						 | 
					@ -152,11 +128,6 @@ void SignupWidget::onCheckRequest() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SignupWidget::onPhotoReady(const QImage &img) {
 | 
					 | 
				
			||||||
	_photoImage = img;
 | 
					 | 
				
			||||||
	_photo->setImage(_photoImage);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SignupWidget::nameSubmitDone(const MTPauth_Authorization &result) {
 | 
					void SignupWidget::nameSubmitDone(const MTPauth_Authorization &result) {
 | 
				
			||||||
	stopCheck();
 | 
						stopCheck();
 | 
				
			||||||
	auto &d = result.c_auth_authorization();
 | 
						auto &d = result.c_auth_authorization();
 | 
				
			||||||
| 
						 | 
					@ -164,7 +135,7 @@ void SignupWidget::nameSubmitDone(const MTPauth_Authorization &result) {
 | 
				
			||||||
		showError(&Lang::Hard::ServerError);
 | 
							showError(&Lang::Hard::ServerError);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	finish(d.vuser, _photoImage);
 | 
						finish(d.vuser, _photo->takeResultImage());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool SignupWidget::nameSubmitFail(const RPCError &error) {
 | 
					bool SignupWidget::nameSubmitFail(const RPCError &error) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 | 
				
			||||||
namespace Ui {
 | 
					namespace Ui {
 | 
				
			||||||
class RoundButton;
 | 
					class RoundButton;
 | 
				
			||||||
class InputField;
 | 
					class InputField;
 | 
				
			||||||
class NewAvatarButton;
 | 
					class UserpicButton;
 | 
				
			||||||
} // namespace Ui
 | 
					} // namespace Ui
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Intro {
 | 
					namespace Intro {
 | 
				
			||||||
| 
						 | 
					@ -48,10 +48,8 @@ protected:
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
	void onInputChange();
 | 
						void onInputChange();
 | 
				
			||||||
	void onCheckRequest();
 | 
						void onCheckRequest();
 | 
				
			||||||
	void onPhotoReady(const QImage &img);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void setupPhotoButton();
 | 
					 | 
				
			||||||
	void refreshLang();
 | 
						void refreshLang();
 | 
				
			||||||
	void updateControlsGeometry();
 | 
						void updateControlsGeometry();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,9 +58,7 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void stopCheck();
 | 
						void stopCheck();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QImage _photoImage;
 | 
						object_ptr<Ui::UserpicButton> _photo;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	object_ptr<Ui::NewAvatarButton> _photo;
 | 
					 | 
				
			||||||
	object_ptr<Ui::InputField> _first;
 | 
						object_ptr<Ui::InputField> _first;
 | 
				
			||||||
	object_ptr<Ui::InputField> _last;
 | 
						object_ptr<Ui::InputField> _last;
 | 
				
			||||||
	QString _firstName, _lastName;
 | 
						QString _firstName, _lastName;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -449,7 +449,7 @@ QString Widget::Step::nextButtonText() const {
 | 
				
			||||||
	return lang(lng_intro_next);
 | 
						return lang(lng_intro_next);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Widget::Step::finish(const MTPUser &user, QImage photo) {
 | 
					void Widget::Step::finish(const MTPUser &user, QImage &&photo) {
 | 
				
			||||||
	if (user.type() != mtpc_user || !user.c_user().is_self()) {
 | 
						if (user.type() != mtpc_user || !user.c_user().is_self()) {
 | 
				
			||||||
		// No idea what to do here.
 | 
							// No idea what to do here.
 | 
				
			||||||
		// We could've reset intro and MTP, but this really should not happen.
 | 
							// We could've reset intro and MTP, but this really should not happen.
 | 
				
			||||||
| 
						 | 
					@ -475,7 +475,9 @@ void Widget::Step::finish(const MTPUser &user, QImage photo) {
 | 
				
			||||||
		Auth().api().requestFullPeer(user);
 | 
							Auth().api().requestFullPeer(user);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!photo.isNull()) {
 | 
						if (!photo.isNull()) {
 | 
				
			||||||
		Messenger::Instance().uploadProfilePhoto(photo, Auth().userId());
 | 
							Messenger::Instance().uploadProfilePhoto(
 | 
				
			||||||
 | 
								std::move(photo),
 | 
				
			||||||
 | 
								Auth().userId());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,7 +147,7 @@ public:
 | 
				
			||||||
		Data *getData() const {
 | 
							Data *getData() const {
 | 
				
			||||||
			return _data;
 | 
								return _data;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		void finish(const MTPUser &user, QImage photo = QImage());
 | 
							void finish(const MTPUser &user, QImage &&photo = QImage());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void goBack() {
 | 
							void goBack() {
 | 
				
			||||||
			if (_goCallback) _goCallback(nullptr, Direction::Back);
 | 
								if (_goCallback) _goCallback(nullptr, Direction::Back);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -849,7 +849,7 @@ bool Messenger::openLocalUrl(const QString &url) {
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Messenger::uploadProfilePhoto(const QImage &tosend, const PeerId &peerId) {
 | 
					void Messenger::uploadProfilePhoto(QImage &&tosend, const PeerId &peerId) {
 | 
				
			||||||
	PreparedPhotoThumbs photoThumbs;
 | 
						PreparedPhotoThumbs photoThumbs;
 | 
				
			||||||
	QVector<MTPPhotoSize> photoSizes;
 | 
						QVector<MTPPhotoSize> photoSizes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,7 +150,7 @@ public:
 | 
				
			||||||
	void checkStartUrl();
 | 
						void checkStartUrl();
 | 
				
			||||||
	bool openLocalUrl(const QString &url);
 | 
						bool openLocalUrl(const QString &url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void uploadProfilePhoto(const QImage &tosend, const PeerId &peerId);
 | 
						void uploadProfilePhoto(QImage &&tosend, const PeerId &peerId);
 | 
				
			||||||
	void regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId);
 | 
						void regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId);
 | 
				
			||||||
	bool isPhotoUpdating(const PeerId &peer);
 | 
						bool isPhotoUpdating(const PeerId &peer);
 | 
				
			||||||
	void cancelPhotoUpdate(const PeerId &peer);
 | 
						void cancelPhotoUpdate(const PeerId &peer);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -362,7 +362,14 @@ void CoverWidget::showSetPhotoBox(const QImage &img) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto box = Ui::show(Box<PhotoCropBox>(img, _self));
 | 
						auto peer = _self;
 | 
				
			||||||
 | 
						auto box = Ui::show(Box<PhotoCropBox>(img, peer));
 | 
				
			||||||
 | 
						box->ready()
 | 
				
			||||||
 | 
							| rpl::start_with_next([=](QImage &&image) {
 | 
				
			||||||
 | 
								Messenger::Instance().uploadProfilePhoto(
 | 
				
			||||||
 | 
									std::move(image),
 | 
				
			||||||
 | 
									peer->id);
 | 
				
			||||||
 | 
							}, box->lifetime());
 | 
				
			||||||
	subscribe(box->boxClosing, [this] { onPhotoUploadStatusChanged(); });
 | 
						subscribe(box->boxClosing, [this] { onPhotoUploadStatusChanged(); });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,12 +24,34 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 | 
				
			||||||
#include "styles/style_history.h"
 | 
					#include "styles/style_history.h"
 | 
				
			||||||
#include "dialogs/dialogs_layout.h"
 | 
					#include "dialogs/dialogs_layout.h"
 | 
				
			||||||
#include "ui/effects/ripple_animation.h"
 | 
					#include "ui/effects/ripple_animation.h"
 | 
				
			||||||
 | 
					#include "data/data_photo.h"
 | 
				
			||||||
 | 
					#include "core/file_utilities.h"
 | 
				
			||||||
 | 
					#include "boxes/photo_crop_box.h"
 | 
				
			||||||
 | 
					#include "boxes/confirm_box.h"
 | 
				
			||||||
 | 
					#include "window/window_controller.h"
 | 
				
			||||||
 | 
					#include "lang/lang_keys.h"
 | 
				
			||||||
 | 
					#include "auth_session.h"
 | 
				
			||||||
 | 
					#include "messenger.h"
 | 
				
			||||||
 | 
					#include "observer_peer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ui {
 | 
					namespace Ui {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constexpr int kWideScale = 5;
 | 
					constexpr int kWideScale = 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Callback>
 | 
				
			||||||
 | 
					QPixmap CreateSquarePixmap(int width, Callback &&paintCallback) {
 | 
				
			||||||
 | 
						auto size = QSize(width, width) * cIntRetinaFactor();
 | 
				
			||||||
 | 
						auto image = QImage(size, QImage::Format_ARGB32_Premultiplied);
 | 
				
			||||||
 | 
						image.setDevicePixelRatio(cRetinaFactor());
 | 
				
			||||||
 | 
						image.fill(Qt::transparent);
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Painter p(&image);
 | 
				
			||||||
 | 
							paintCallback(p);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return App::pixmapFromImageInPlace(std::move(image));
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HistoryDownButton::HistoryDownButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple)
 | 
					HistoryDownButton::HistoryDownButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple)
 | 
				
			||||||
| 
						 | 
					@ -311,41 +333,321 @@ void PeerAvatarButton::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NewAvatarButton::NewAvatarButton(QWidget *parent, int size, QPoint position) : RippleButton(parent, st::defaultActiveButton.ripple)
 | 
					UserpicButton::UserpicButton(
 | 
				
			||||||
, _position(position) {
 | 
						QWidget *parent,
 | 
				
			||||||
	resize(size, size);
 | 
						PeerId peerForCrop,
 | 
				
			||||||
 | 
						Role role,
 | 
				
			||||||
 | 
						const style::UserpicButton &st)
 | 
				
			||||||
 | 
					: RippleButton(parent, st.changeButton.ripple)
 | 
				
			||||||
 | 
					, _st(st)
 | 
				
			||||||
 | 
					, _peerForCrop(peerForCrop)
 | 
				
			||||||
 | 
					, _role(role) {
 | 
				
			||||||
 | 
						Expects(_role == Role::ChangePhoto);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_waiting = false;
 | 
				
			||||||
 | 
						prepare();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewAvatarButton::paintEvent(QPaintEvent *e) {
 | 
					UserpicButton::UserpicButton(
 | 
				
			||||||
	Painter p(this);
 | 
						QWidget *parent,
 | 
				
			||||||
 | 
						not_null<Window::Controller*> controller,
 | 
				
			||||||
 | 
						not_null<PeerData*> peer,
 | 
				
			||||||
 | 
						Role role,
 | 
				
			||||||
 | 
						const style::UserpicButton &st)
 | 
				
			||||||
 | 
					: RippleButton(parent, st.changeButton.ripple)
 | 
				
			||||||
 | 
					, _st(st)
 | 
				
			||||||
 | 
					, _controller(controller)
 | 
				
			||||||
 | 
					, _peer(peer)
 | 
				
			||||||
 | 
					, _peerForCrop(_peer->id)
 | 
				
			||||||
 | 
					, _role(role) {
 | 
				
			||||||
 | 
						processPeerPhoto();
 | 
				
			||||||
 | 
						prepare();
 | 
				
			||||||
 | 
						setupPeerViewers();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!_image.isNull()) {
 | 
					void UserpicButton::prepare() {
 | 
				
			||||||
		p.drawPixmap(0, 0, _image);
 | 
						resize(_st.size);
 | 
				
			||||||
 | 
						_notShownYet = _waiting;
 | 
				
			||||||
 | 
						if (!_waiting) {
 | 
				
			||||||
 | 
							prepareUserpicPixmap();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						setClickHandlerByRole();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::setClickHandlerByRole() {
 | 
				
			||||||
 | 
						switch (_role) {
 | 
				
			||||||
 | 
						case Role::ChangePhoto:
 | 
				
			||||||
 | 
							addClickHandler(App::LambdaDelayed(
 | 
				
			||||||
 | 
								_st.changeButton.ripple.hideDuration,
 | 
				
			||||||
 | 
								this,
 | 
				
			||||||
 | 
								[this] { changePhotoLazy(); }));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case Role::OpenPhoto:
 | 
				
			||||||
 | 
							addClickHandler([this] {
 | 
				
			||||||
 | 
								openPeerPhoto();
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case Role::OpenProfile:
 | 
				
			||||||
 | 
							addClickHandler([this] {
 | 
				
			||||||
 | 
								Expects(_controller != nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								_controller->showPeerInfo(_peer);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::changePhotoLazy() {
 | 
				
			||||||
 | 
						auto imgExtensions = cImgExtensions();
 | 
				
			||||||
 | 
						auto filter = qsl("Image files (*")
 | 
				
			||||||
 | 
							+ imgExtensions.join(qsl(" *"))
 | 
				
			||||||
 | 
							+ qsl(");;")
 | 
				
			||||||
 | 
							+ FileDialog::AllFilesFilter();
 | 
				
			||||||
 | 
						auto handleChosenPhoto = base::lambda_guarded(
 | 
				
			||||||
 | 
							this,
 | 
				
			||||||
 | 
							[this](auto &&result) { suggestPhotoFile(result); });
 | 
				
			||||||
 | 
						FileDialog::GetOpenPath(
 | 
				
			||||||
 | 
							lang(lng_choose_image),
 | 
				
			||||||
 | 
							filter,
 | 
				
			||||||
 | 
							std::move(handleChosenPhoto));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::suggestPhotoFile(
 | 
				
			||||||
 | 
							const FileDialog::OpenResult &result) {
 | 
				
			||||||
 | 
						if (result.paths.isEmpty() && result.remoteContent.isEmpty()) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p.setPen(Qt::NoPen);
 | 
						auto image = [&] {
 | 
				
			||||||
	p.setBrush(isOver() ? st::defaultActiveButton.textBgOver : st::defaultActiveButton.textBg);
 | 
							if (!result.remoteContent.isEmpty()) {
 | 
				
			||||||
	{
 | 
								return App::readImage(result.remoteContent);
 | 
				
			||||||
		PainterHighQualityEnabler hq(p);
 | 
							} else if (!result.paths.isEmpty()) {
 | 
				
			||||||
		p.drawEllipse(rect());
 | 
								return App::readImage(result.paths.front());
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
							return QImage();
 | 
				
			||||||
	paintRipple(p, 0, 0, getms());
 | 
						}();
 | 
				
			||||||
 | 
						suggestPhoto(image);
 | 
				
			||||||
	st::newGroupPhotoIcon.paint(p, _position, width());
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewAvatarButton::setImage(const QImage &image) {
 | 
					void UserpicButton::suggestPhoto(const QImage &image) {
 | 
				
			||||||
	auto small = image.scaled(size() * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
 | 
						auto badAspect = [](int a, int b) {
 | 
				
			||||||
	Images::prepareCircle(small);
 | 
							return (a >= 10 * b);
 | 
				
			||||||
	_image = App::pixmapFromImageInPlace(std::move(small));
 | 
						};
 | 
				
			||||||
	_image.setDevicePixelRatio(cRetinaFactor());
 | 
						if (image.isNull()
 | 
				
			||||||
 | 
							|| badAspect(image.width(), image.height())
 | 
				
			||||||
 | 
							|| badAspect(image.height(), image.width())) {
 | 
				
			||||||
 | 
							Ui::show(
 | 
				
			||||||
 | 
								Box<InformBox>(lang(lng_bad_photo)),
 | 
				
			||||||
 | 
								LayerOption::KeepOther);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto box = Ui::show(
 | 
				
			||||||
 | 
							Box<PhotoCropBox>(image, _peerForCrop),
 | 
				
			||||||
 | 
							LayerOption::KeepOther);
 | 
				
			||||||
 | 
						box->ready()
 | 
				
			||||||
 | 
							| rpl::start_with_next([this](QImage &&image) {
 | 
				
			||||||
 | 
								setImage(std::move(image));
 | 
				
			||||||
 | 
							}, box->lifetime());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::openPeerPhoto() {
 | 
				
			||||||
 | 
						Expects(_peer != nullptr);
 | 
				
			||||||
 | 
						Expects(_controller != nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto id = _peer->photoId;
 | 
				
			||||||
 | 
						if (!id || id == UnknownPeerPhotoId) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						auto photo = App::photo(id);
 | 
				
			||||||
 | 
						if (photo->date) {
 | 
				
			||||||
 | 
							Messenger::Instance().showPhoto(photo, _peer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::setupPeerViewers() {
 | 
				
			||||||
 | 
						Notify::PeerUpdateViewer(
 | 
				
			||||||
 | 
							_peer,
 | 
				
			||||||
 | 
							Notify::PeerUpdate::Flag::PhotoChanged)
 | 
				
			||||||
 | 
							| rpl::start_with_next([this] {
 | 
				
			||||||
 | 
								processNewPeerPhoto();
 | 
				
			||||||
 | 
								update();
 | 
				
			||||||
 | 
							}, lifetime());
 | 
				
			||||||
 | 
						base::ObservableViewer(Auth().downloaderTaskFinished())
 | 
				
			||||||
 | 
							| rpl::start_with_next([this] {
 | 
				
			||||||
 | 
								if (_waiting && _peer->userpicLoaded()) {
 | 
				
			||||||
 | 
									_waiting = false;
 | 
				
			||||||
 | 
									startNewPhotoShowing();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}, lifetime());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
 | 
						Painter p(this);
 | 
				
			||||||
 | 
						if (!_waiting && _notShownYet) {
 | 
				
			||||||
 | 
							_notShownYet = false;
 | 
				
			||||||
 | 
							startAnimation();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto photoPosition = countPhotoPosition();
 | 
				
			||||||
 | 
						auto photoLeft = photoPosition.x();
 | 
				
			||||||
 | 
						auto photoTop = photoPosition.y();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto ms = getms();
 | 
				
			||||||
 | 
						if (_a_appearance.animating(ms)) {
 | 
				
			||||||
 | 
							p.drawPixmapLeft(photoPosition, width(), _oldUserpic);
 | 
				
			||||||
 | 
							p.setOpacity(_a_appearance.current());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p.drawPixmapLeft(photoPosition, width(), _userpic);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (_role == Role::ChangePhoto) {
 | 
				
			||||||
 | 
							auto over = isOver() || isDown();
 | 
				
			||||||
 | 
							if (over) {
 | 
				
			||||||
 | 
								PainterHighQualityEnabler hq(p);
 | 
				
			||||||
 | 
								p.setPen(Qt::NoPen);
 | 
				
			||||||
 | 
								p.setBrush(_userpicHasImage
 | 
				
			||||||
 | 
									? st::msgDateImgBg
 | 
				
			||||||
 | 
									: _st.changeButton.textBgOver);
 | 
				
			||||||
 | 
								p.drawEllipse(
 | 
				
			||||||
 | 
									photoLeft,
 | 
				
			||||||
 | 
									photoTop,
 | 
				
			||||||
 | 
									_st.photoSize,
 | 
				
			||||||
 | 
									_st.photoSize);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							paintRipple(
 | 
				
			||||||
 | 
								p,
 | 
				
			||||||
 | 
								photoLeft,
 | 
				
			||||||
 | 
								photoTop,
 | 
				
			||||||
 | 
								ms,
 | 
				
			||||||
 | 
								_userpicHasImage
 | 
				
			||||||
 | 
									? &st::shadowFg->c
 | 
				
			||||||
 | 
									: &_st.changeButton.ripple.color->c);
 | 
				
			||||||
 | 
							if (over || !_userpicHasImage) {
 | 
				
			||||||
 | 
								auto iconLeft = (_st.changeIconPosition.x() < 0)
 | 
				
			||||||
 | 
									? (_st.photoSize - _st.changeIcon.width()) / 2
 | 
				
			||||||
 | 
									: _st.changeIconPosition.x();
 | 
				
			||||||
 | 
								auto iconTop = (_st.changeIconPosition.y() < 0)
 | 
				
			||||||
 | 
									? (_st.photoSize - _st.changeIcon.height()) / 2
 | 
				
			||||||
 | 
									: _st.changeIconPosition.y();
 | 
				
			||||||
 | 
								_st.changeIcon.paint(
 | 
				
			||||||
 | 
									p,
 | 
				
			||||||
 | 
									photoLeft + iconLeft,
 | 
				
			||||||
 | 
									photoTop + iconTop,
 | 
				
			||||||
 | 
									width());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QPoint UserpicButton::countPhotoPosition() const {
 | 
				
			||||||
 | 
						auto photoLeft = (_st.photoPosition.x() < 0)
 | 
				
			||||||
 | 
							? (width() - _st.photoSize) / 2
 | 
				
			||||||
 | 
							: _st.photoPosition.x();
 | 
				
			||||||
 | 
						auto photoTop = (_st.photoPosition.y() < 0)
 | 
				
			||||||
 | 
							? (height() - _st.photoSize) / 2
 | 
				
			||||||
 | 
							: _st.photoPosition.y();
 | 
				
			||||||
 | 
						return { photoLeft, photoTop };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QImage UserpicButton::prepareRippleMask() const {
 | 
				
			||||||
 | 
						return Ui::RippleAnimation::ellipseMask(QSize(
 | 
				
			||||||
 | 
							_st.photoSize,
 | 
				
			||||||
 | 
							_st.photoSize));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QPoint UserpicButton::prepareRippleStartPosition() const {
 | 
				
			||||||
 | 
						return (_role == Role::ChangePhoto)
 | 
				
			||||||
 | 
							? mapFromGlobal(QCursor::pos()) - countPhotoPosition()
 | 
				
			||||||
 | 
							: DisabledRippleStartPosition();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::processPeerPhoto() {
 | 
				
			||||||
 | 
						Expects(_peer != nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool hasPhoto = (_peer->photoId && _peer->photoId != UnknownPeerPhotoId);
 | 
				
			||||||
 | 
						setCursor(hasPhoto ? style::cur_pointer : style::cur_default);
 | 
				
			||||||
 | 
						_waiting = !_peer->userpicLoaded();
 | 
				
			||||||
 | 
						if (_waiting) {
 | 
				
			||||||
 | 
							_peer->loadUserpic(true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (_role == Role::OpenPhoto) {
 | 
				
			||||||
 | 
							auto id = _peer->photoId;
 | 
				
			||||||
 | 
							if (id == UnknownPeerPhotoId) {
 | 
				
			||||||
 | 
								_peer->updateFull();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							auto canOpen = (id != 0 && id != UnknownPeerPhotoId);
 | 
				
			||||||
 | 
							setCursor(canOpen ? style::cur_pointer : style::cur_default);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::processNewPeerPhoto() {
 | 
				
			||||||
 | 
						if (_userpicCustom) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						processPeerPhoto();
 | 
				
			||||||
 | 
						if (!_waiting) {
 | 
				
			||||||
 | 
							_oldUserpic = myGrab(this);
 | 
				
			||||||
 | 
							startNewPhotoShowing();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::startNewPhotoShowing() {
 | 
				
			||||||
 | 
						prepareUserpicPixmap();
 | 
				
			||||||
 | 
						if (_notShownYet) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						startAnimation();
 | 
				
			||||||
	update();
 | 
						update();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QImage NewAvatarButton::prepareRippleMask() const {
 | 
					void UserpicButton::startAnimation() {
 | 
				
			||||||
	return Ui::RippleAnimation::ellipseMask(size());
 | 
						_a_appearance.finish();
 | 
				
			||||||
 | 
						_a_appearance.start([this] { update(); }, 0, 1, _st.duration);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::switchChangePhotoOverlay(bool enabled) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::setImage(QImage &&image) {
 | 
				
			||||||
 | 
						_oldUserpic = myGrab(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto size = QSize(_st.photoSize, _st.photoSize);
 | 
				
			||||||
 | 
						auto small = image.scaled(
 | 
				
			||||||
 | 
							size * cIntRetinaFactor(),
 | 
				
			||||||
 | 
							Qt::IgnoreAspectRatio,
 | 
				
			||||||
 | 
							Qt::SmoothTransformation);
 | 
				
			||||||
 | 
						Images::prepareCircle(small);
 | 
				
			||||||
 | 
						_userpic = App::pixmapFromImageInPlace(std::move(small));
 | 
				
			||||||
 | 
						_userpic.setDevicePixelRatio(cRetinaFactor());
 | 
				
			||||||
 | 
						_userpicCustom = _userpicHasImage = true;
 | 
				
			||||||
 | 
						_result = std::move(image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						startNewPhotoShowing();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UserpicButton::prepareUserpicPixmap() {
 | 
				
			||||||
 | 
						if (_userpicCustom) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						auto size = _st.photoSize;
 | 
				
			||||||
 | 
						auto paintButton = [&](Painter &p, const style::color &color) {
 | 
				
			||||||
 | 
							PainterHighQualityEnabler hq(p);
 | 
				
			||||||
 | 
							p.setBrush(color);
 | 
				
			||||||
 | 
							p.setPen(Qt::NoPen);
 | 
				
			||||||
 | 
							p.drawEllipse(0, 0, size, size);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						_userpicHasImage = _peer
 | 
				
			||||||
 | 
							? (_peer->currentUserpic() || _role != Role::ChangePhoto)
 | 
				
			||||||
 | 
							: false;
 | 
				
			||||||
 | 
						_userpic = CreateSquarePixmap(size, [&](Painter &p) {
 | 
				
			||||||
 | 
							if (_userpicHasImage) {
 | 
				
			||||||
 | 
								_peer->paintUserpic(p, 0, 0, _st.photoSize);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								paintButton(p, _st.changeButton.textBg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Ui
 | 
					} // namespace Ui
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PeerData;
 | 
					class PeerData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Window {
 | 
				
			||||||
 | 
					class Controller;
 | 
				
			||||||
 | 
					} // namespace Window
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FileDialog {
 | 
				
			||||||
 | 
					struct OpenResult;
 | 
				
			||||||
 | 
					} // namespace FileDialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ui {
 | 
					namespace Ui {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class HistoryDownButton : public RippleButton {
 | 
					class HistoryDownButton : public RippleButton {
 | 
				
			||||||
| 
						 | 
					@ -162,24 +170,69 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NewAvatarButton : public RippleButton {
 | 
					class UserpicButton : public RippleButton {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	NewAvatarButton(QWidget *parent, int size, QPoint position);
 | 
						enum class Role {
 | 
				
			||||||
 | 
							ChangePhoto,
 | 
				
			||||||
 | 
							OpenPhoto,
 | 
				
			||||||
 | 
							OpenProfile,
 | 
				
			||||||
 | 
							Custom,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setImage(const QImage &image);
 | 
						UserpicButton(
 | 
				
			||||||
 | 
							QWidget *parent,
 | 
				
			||||||
 | 
							PeerId peerForCrop,
 | 
				
			||||||
 | 
							Role role,
 | 
				
			||||||
 | 
							const style::UserpicButton &st);
 | 
				
			||||||
 | 
						UserpicButton(
 | 
				
			||||||
 | 
							QWidget *parent,
 | 
				
			||||||
 | 
							not_null<Window::Controller*> controller,
 | 
				
			||||||
 | 
							not_null<PeerData*> peer,
 | 
				
			||||||
 | 
							Role role,
 | 
				
			||||||
 | 
							const style::UserpicButton &st);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int naturalWidth() const override {
 | 
						void switchChangePhotoOverlay(bool enabled);
 | 
				
			||||||
		return height();
 | 
					
 | 
				
			||||||
 | 
						QImage takeResultImage() {
 | 
				
			||||||
 | 
							return std::move(_result);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	void paintEvent(QPaintEvent *e) override;
 | 
						void paintEvent(QPaintEvent *e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QImage prepareRippleMask() const override;
 | 
						QImage prepareRippleMask() const override;
 | 
				
			||||||
 | 
						QPoint prepareRippleStartPosition() const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	QPixmap _image;
 | 
						void prepare();
 | 
				
			||||||
	QPoint _position;
 | 
						void setImage(QImage &&image);
 | 
				
			||||||
 | 
						void setupPeerViewers();
 | 
				
			||||||
 | 
						void startAnimation();
 | 
				
			||||||
 | 
						void processPeerPhoto();
 | 
				
			||||||
 | 
						void processNewPeerPhoto();
 | 
				
			||||||
 | 
						void startNewPhotoShowing();
 | 
				
			||||||
 | 
						void prepareUserpicPixmap();
 | 
				
			||||||
 | 
						QPoint countPhotoPosition() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void setClickHandlerByRole();
 | 
				
			||||||
 | 
						void openPeerPhoto();
 | 
				
			||||||
 | 
						void changePhotoLazy();
 | 
				
			||||||
 | 
						void suggestPhotoFile(
 | 
				
			||||||
 | 
							const FileDialog::OpenResult &result);
 | 
				
			||||||
 | 
						void suggestPhoto(const QImage &image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const style::UserpicButton &_st;
 | 
				
			||||||
 | 
						Window::Controller *_controller = nullptr;
 | 
				
			||||||
 | 
						PeerData *_peer = nullptr;
 | 
				
			||||||
 | 
						PeerId _peerForCrop = 0;
 | 
				
			||||||
 | 
						Role _role = Role::ChangePhoto;
 | 
				
			||||||
 | 
						bool _notShownYet = true;
 | 
				
			||||||
 | 
						bool _waiting = false;
 | 
				
			||||||
 | 
						QPixmap _userpic, _oldUserpic;
 | 
				
			||||||
 | 
						bool _userpicHasImage = false;
 | 
				
			||||||
 | 
						bool _userpicCustom = false;
 | 
				
			||||||
 | 
						Animation _a_appearance;
 | 
				
			||||||
 | 
						QImage _result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -497,6 +497,16 @@ PeerAvatarButton {
 | 
				
			||||||
	photoSize: pixels;
 | 
						photoSize: pixels;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UserpicButton {
 | 
				
			||||||
 | 
						size: size;
 | 
				
			||||||
 | 
						photoSize: pixels;
 | 
				
			||||||
 | 
						photoPosition: point;
 | 
				
			||||||
 | 
						changeButton: RoundButton;
 | 
				
			||||||
 | 
						changeIcon: icon;
 | 
				
			||||||
 | 
						changeIconPosition: point;
 | 
				
			||||||
 | 
						duration: int;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
InfoProfileButton {
 | 
					InfoProfileButton {
 | 
				
			||||||
	textFg: color;
 | 
						textFg: color;
 | 
				
			||||||
	textFgOver: color;
 | 
						textFgOver: color;
 | 
				
			||||||
| 
						 | 
					@ -975,6 +985,16 @@ defaultImportantTooltipLabel: FlatLabel(defaultFlatLabel) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultUserpicButton: UserpicButton {
 | 
				
			||||||
 | 
						size: size(76px, 76px);
 | 
				
			||||||
 | 
						photoSize: 76px;
 | 
				
			||||||
 | 
						photoPosition: point(-1px, -1px);
 | 
				
			||||||
 | 
						changeButton: defaultActiveButton;
 | 
				
			||||||
 | 
						changeIcon: icon {{ "new_chat_photo", activeButtonFg }};
 | 
				
			||||||
 | 
						changeIconPosition: point(23px, 25px);
 | 
				
			||||||
 | 
						duration: 500;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
historyToDownBelow: icon {
 | 
					historyToDownBelow: icon {
 | 
				
			||||||
	{ "history_down_shadow", historyToDownShadow },
 | 
						{ "history_down_shadow", historyToDownShadow },
 | 
				
			||||||
	{ "history_down_circle", historyToDownBg, point(4px, 4px) },
 | 
						{ "history_down_circle", historyToDownBg, point(4px, 4px) },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -350,7 +350,7 @@ void Filler::addChatActions(not_null<ChatData*> chat) {
 | 
				
			||||||
	if (_source != PeerMenuSource::ChatsList) {
 | 
						if (_source != PeerMenuSource::ChatsList) {
 | 
				
			||||||
		if (chat->canEdit()) {
 | 
							if (chat->canEdit()) {
 | 
				
			||||||
			_addAction(
 | 
								_addAction(
 | 
				
			||||||
				lang(lng_profile_edit_contact),
 | 
									lang(lng_profile_edit_group_name),
 | 
				
			||||||
				[chat] { Ui::show(Box<EditNameTitleBox>(chat)); });
 | 
									[chat] { Ui::show(Box<EditNameTitleBox>(chat)); });
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (chat->amCreator()
 | 
							if (chat->amCreator()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue