diff --git a/Telegram/Resources/icons/settings/photo.png b/Telegram/Resources/icons/settings/photo.png new file mode 100644 index 000000000..ef6d4e0a6 Binary files /dev/null and b/Telegram/Resources/icons/settings/photo.png differ diff --git a/Telegram/Resources/icons/settings/photo@2x.png b/Telegram/Resources/icons/settings/photo@2x.png new file mode 100644 index 000000000..845623e7e Binary files /dev/null and b/Telegram/Resources/icons/settings/photo@2x.png differ diff --git a/Telegram/Resources/icons/settings/photo@3x.png b/Telegram/Resources/icons/settings/photo@3x.png new file mode 100644 index 000000000..1258fa5e2 Binary files /dev/null and b/Telegram/Resources/icons/settings/photo@3x.png differ diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index b2390d04b..e361c9cfe 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -142,9 +142,18 @@ settingsInfoPhoto: UserpicButton(defaultUserpicButton) { size: size(settingsInfoPhotoSize, settingsInfoPhotoSize); photoSize: settingsInfoPhotoSize; } +settingsInfoUploadSize: 32px; +settingsInfoUpload: UserpicButton(defaultUserpicButton) { + size: size(settingsInfoUploadSize, settingsInfoUploadSize); + photoSize: settingsInfoUploadSize; + changeIcon: icon {{ "settings/photo", activeButtonFg }}; + changeIconPosition: point(4px, 4px); +} +settingsInfoUploadBorder: 2px; settingsInfoPhotoTop: 0px; settingsInfoPhotoSkip: 7px; settingsInfoNameSkip: -1px; +settingsInfoUploadLeft: 6px; settingsBio: InputField(defaultInputField) { textBg: transparent; diff --git a/Telegram/SourceFiles/settings/settings_information.cpp b/Telegram/SourceFiles/settings/settings_information.cpp index 340e523c2..8b67a6845 100644 --- a/Telegram/SourceFiles/settings/settings_information.cpp +++ b/Telegram/SourceFiles/settings/settings_information.cpp @@ -111,6 +111,40 @@ private: }; } +[[nodiscard]] not_null CreateUploadButton( + not_null parent, + not_null controller) { + const auto background = Ui::CreateChild(parent.get()); + const auto upload = Ui::CreateChild( + parent.get(), + &controller->window(), + tr::lng_settings_crop_profile(tr::now), + Ui::UserpicButton::Role::ChoosePhoto, + st::settingsInfoUpload); + + const auto border = st::settingsInfoUploadBorder; + const auto size = upload->rect().marginsAdded( + { border, border, border, border } + ).size(); + + background->resize(size); + background->paintRequest( + ) | rpl::start_with_next([=] { + auto p = QPainter(background); + auto hq = PainterHighQualityEnabler(p); + p.setBrush(st::boxBg); + p.setPen(Qt::NoPen); + p.drawEllipse(background->rect()); + }, background->lifetime()); + + upload->positionValue( + ) | rpl::start_with_next([=](QPoint position) { + background->move(position - QPoint(border, border)); + }, background->lifetime()); + + return upload; +} + void SetupPhoto( not_null container, not_null controller, @@ -124,6 +158,15 @@ void SetupPhoto( self, Ui::UserpicButton::Role::OpenPhoto, st::settingsInfoPhoto); + const auto upload = CreateUploadButton(wrap, controller); + + upload->chosenImages( + ) | rpl::start_with_next([=](QImage &&image) { + self->session().api().peerPhoto().upload( + self, + base::duplicate(image)); + photo->changeTo(std::move(image)); + }, upload->lifetime()); const auto name = Ui::CreateChild( wrap, @@ -146,6 +189,12 @@ void SetupPhoto( photo->moveToLeft( (max - photoWidth) / 2, st::settingsInfoPhotoTop); + upload->moveToLeft( + ((max - photoWidth) / 2 + + photoWidth + - upload->width() + + st::settingsInfoUploadLeft), + photo->y() + photo->height() - upload->height()); name->moveToLeft( (max - nameWidth) / 2, (photo->y() + photo->height() + st::settingsInfoPhotoSkip)); diff --git a/Telegram/SourceFiles/settings/settings_main.cpp b/Telegram/SourceFiles/settings/settings_main.cpp index 8300eb11c..5906aed48 100644 --- a/Telegram/SourceFiles/settings/settings_main.cpp +++ b/Telegram/SourceFiles/settings/settings_main.cpp @@ -113,7 +113,6 @@ Cover::Cover( setupChildGeometry(); _userpic->switchChangePhotoOverlay(_user->isSelf()); - _userpic->uploadPhotoRequests( ) | rpl::start_with_next([=] { _user->session().api().peerPhoto().upload( diff --git a/Telegram/SourceFiles/ui/special_buttons.cpp b/Telegram/SourceFiles/ui/special_buttons.cpp index b47d48534..271a9949c 100644 --- a/Telegram/SourceFiles/ui/special_buttons.cpp +++ b/Telegram/SourceFiles/ui/special_buttons.cpp @@ -190,7 +190,7 @@ UserpicButton::UserpicButton( , _window(window) , _cropTitle(cropTitle) , _role(role) { - Expects(_role == Role::ChangePhoto); + Expects(_role == Role::ChangePhoto || _role == Role::ChoosePhoto); _waiting = false; prepare(); @@ -239,10 +239,24 @@ void UserpicButton::prepare() { prepareUserpicPixmap(); } setClickHandlerByRole(); + + if (_role == Role::ChangePhoto) { + chosenImages( + ) | rpl::start_with_next([=](QImage &&image) { + setImage(std::move(image)); + if (_requestToUpload) { + _uploadPhotoRequests.fire({}); + } + }, lifetime()); + } } void UserpicButton::setClickHandlerByRole() { switch (_role) { + case Role::ChoosePhoto: + addClickHandler([=] { choosePhotoLocally(); }); + break; + case Role::ChangePhoto: addClickHandler([=] { changePhotoLocally(); }); break; @@ -263,25 +277,26 @@ void UserpicButton::setClickHandlerByRole() { } } -void UserpicButton::changePhotoLocally(bool requestToUpload) { +void UserpicButton::changeTo(QImage &&image) { + setImage(std::move(image)); +} + +void UserpicButton::choosePhotoLocally() { if (!_window) { return; } auto callback = [=](QImage &&image) { - setImage(std::move(image)); - if (requestToUpload) { - _uploadPhotoRequests.fire({}); - } + _chosenImages.fire(std::move(image)); }; const auto chooseFile = [=] { base::call_delayed( _st.changeButton.ripple.hideDuration, crl::guard(this, [=] { - Editor::PrepareProfilePhotoFromFile( + Editor::PrepareProfilePhotoFromFile( this, _window, callback); - })); + })); }; if (!IsCameraAvailable()) { chooseFile(); @@ -295,6 +310,11 @@ void UserpicButton::changePhotoLocally(bool requestToUpload) { } } +void UserpicButton::changePhotoLocally(bool requestToUpload) { + _requestToUpload = requestToUpload; + choosePhotoLocally(); +} + void UserpicButton::openPeerPhoto() { Expects(_peer != nullptr); Expects(_controller != nullptr); @@ -368,7 +388,7 @@ void UserpicButton::paintEvent(QPaintEvent *e) { paintUserpicFrame(p, photoPosition); } - if (_role == Role::ChangePhoto) { + if (_role == Role::ChangePhoto || _role == Role::ChoosePhoto) { auto over = isOver() || isDown(); if (over) { PainterHighQualityEnabler hq(p); @@ -789,10 +809,6 @@ void UserpicButton::prepareUserpicPixmap() { : InMemoryKey(); } -rpl::producer<> UserpicButton::uploadPhotoRequests() const { - return _uploadPhotoRequests.events(); -} - SilentToggle::SilentToggle(QWidget *parent, not_null channel) : RippleButton(parent, st::historySilentToggle.ripple) , _st(st::historySilentToggle) diff --git a/Telegram/SourceFiles/ui/special_buttons.h b/Telegram/SourceFiles/ui/special_buttons.h index 56cddef54..d744d07da 100644 --- a/Telegram/SourceFiles/ui/special_buttons.h +++ b/Telegram/SourceFiles/ui/special_buttons.h @@ -63,6 +63,7 @@ private: class UserpicButton : public RippleButton { public: enum class Role { + ChoosePhoto, ChangePhoto, OpenPhoto, OpenProfile, @@ -96,12 +97,22 @@ public: void switchChangePhotoOverlay(bool enabled); void showSavedMessagesOnSelf(bool enabled); - rpl::producer<> uploadPhotoRequests() const; + // Role::ChoosePhoto + [[nodiscard]] rpl::producer chosenImages() const { + return _chosenImages.events(); + } - QImage takeResultImage() { + // Role::ChangePhoto + [[nodiscard]] rpl::producer<> uploadPhotoRequests() const { + return _uploadPhotoRequests.events(); + } + [[nodiscard]] QImage takeResultImage() { return std::move(_result); } + // For Role::OpenPhoto as if it is Role::ChangePhoto. + void changeTo(QImage &&image); + protected: void paintEvent(QPaintEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; @@ -140,6 +151,7 @@ private: void grabOldUserpic(); void setClickHandlerByRole(); void openPeerPhoto(); + void choosePhotoLocally(); void changePhotoLocally(bool requestToUpload = false); const style::UserpicButton &_st; @@ -154,6 +166,7 @@ private: QPixmap _userpic, _oldUserpic; bool _userpicHasImage = false; bool _userpicCustom = false; + bool _requestToUpload = false; InMemoryKey _userpicUniqueKey; Ui::Animations::Simple _a_appearance; QImage _result; @@ -168,6 +181,7 @@ private: bool _changeOverlayEnabled = false; Ui::Animations::Simple _changeOverlayShown; + rpl::event_stream _chosenImages; rpl::event_stream<> _uploadPhotoRequests; };