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