From 0dfbb8a5aedfc0bae97f02af16a461005b113504 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 17 Nov 2025 13:44:21 +0300 Subject: [PATCH] Added ability to set group or channel photo from profile top bar. --- Telegram/Resources/langs/lang.strings | 2 + .../info/profile/info_profile_top_bar.cpp | 149 +++++++++++------- 2 files changed, 96 insertions(+), 55 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index d67f85c763..e921acd9bd 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1683,6 +1683,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_profile_suggest_photo" = "Suggest Profile Photo"; "lng_profile_suggest_photo_from_clipboard" = "Suggest From Clipboard"; "lng_profile_set_photo_for" = "Set Profile Photo"; +"lng_profile_set_photo_for_group" = "Set Group Photo"; +"lng_profile_set_photo_for_channel" = "Set Channel Photo"; "lng_profile_set_photo_for_from_clipboard" = "Set From Clipboard"; "lng_profile_set_photo_for_about" = "You can replace {user}'s photo with another photo that only you will see."; "lng_profile_photo_reset" = "Reset to Original"; diff --git a/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp b/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp index 8ce247fc9a..d031f9d291 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp @@ -910,31 +910,6 @@ void TopBar::setupUserpicButton( not_null controller) { _userpicButton = base::make_unique_q(this); - const auto invalidate = [=] { - _userpicUniqueKey = InMemoryKey(); - _userpicButton->setAttribute( - Qt::WA_TransparentForMouseEvents, - !_peer->userpicPhotoId() && !_hasStories); - updateVideoUserpic(); - }; - - rpl::single( - rpl::empty_value() - ) | rpl::then( - _peer->session().changes().peerFlagsValue( - _peer, - Data::PeerUpdate::Flag::Photo - | Data::PeerUpdate::Flag::FullInfo) | rpl::to_empty - ) | rpl::start_with_next(invalidate, lifetime()); - - if (const auto broadcast = _peer->monoforumBroadcast()) { - _peer->session().changes().peerFlagsValue( - broadcast, - Data::PeerUpdate::Flag::Photo - | Data::PeerUpdate::Flag::FullInfo - ) | rpl::to_empty | rpl::start_with_next(invalidate, lifetime()); - } - const auto openPhoto = [=, peer = _peer] { if (const auto id = peer->userpicPhotoId()) { if (const auto photo = peer->owner().photo(id); photo->date()) { @@ -967,13 +942,19 @@ void TopBar::setupUserpicButton( return true; }; - const auto isContact = [=, peer = _peer] { + const auto canChangePhoto = [=, peer = _peer] { if (const auto user = peer->asUser()) { return user->isContact() && !user->isSelf() && !user->isInaccessible() && !user->isServiceUser(); } + if (const auto chat = peer->asChat()) { + return chat->canEditInformation(); + } + if (const auto channel = peer->asChannel()) { + return channel->canEditInformation(); + } return false; }; @@ -987,9 +968,53 @@ void TopBar::setupUserpicButton( return false; }; - const auto choosePhotoCallback = [=](Ui::UserpicButton::ChosenType type) { + const auto hasMenu = [=] { + if (canChangePhoto()) { + return true; + } + if (canSuggestPhoto()) { + return true; + } + if (_hasStories || canReport()) { + return !!_peer->userpicPhotoId(); + } + return false; + }; + + const auto invalidate = [=] { + _userpicUniqueKey = InMemoryKey(); + const auto hasLeftButton = _peer->userpicPhotoId() || _hasStories; + _userpicButton->setAttribute( + Qt::WA_TransparentForMouseEvents, + !hasLeftButton && !hasMenu()); + _userpicButton->setPointerCursor(hasLeftButton); + updateVideoUserpic(); + Ui::PostponeCall(this, [=] { + update(); + }); + }; + + rpl::single( + rpl::empty_value() + ) | rpl::then( + _peer->session().changes().peerFlagsValue( + _peer, + Data::PeerUpdate::Flag::Photo + | Data::PeerUpdate::Flag::FullInfo) | rpl::to_empty + ) | rpl::start_with_next(invalidate, lifetime()); + + if (const auto broadcast = _peer->monoforumBroadcast()) { + _peer->session().changes().peerFlagsValue( + broadcast, + Data::PeerUpdate::Flag::Photo + | Data::PeerUpdate::Flag::FullInfo + ) | rpl::to_empty | rpl::start_with_next(invalidate, lifetime()); + } + + using ChosenType = Ui::UserpicButton::ChosenType; + + const auto choosePhotoCallback = [=](ChosenType type) { return [=](QImage &&image) { - using ChosenType = Ui::UserpicButton::ChosenType; auto result = Api::PeerPhoto::UserPhoto{ std::move(image), 0, @@ -1010,12 +1035,12 @@ void TopBar::setupUserpicButton( }; }; - const auto editorData = [=](Ui::UserpicButton::ChosenType type) { + const auto editorData = [=](ChosenType type) { const auto user = _peer->asUser(); const auto name = (user && !user->firstName.isEmpty()) ? user->firstName : _peer->name(); - const auto phrase = (type == Ui::UserpicButton::ChosenType::Suggest) + const auto phrase = (type == ChosenType::Suggest) ? &tr::lng_profile_suggest_sure : &tr::lng_profile_set_personal_sure; return Editor::EditorData{ @@ -1024,7 +1049,7 @@ void TopBar::setupUserpicButton( lt_user, Ui::Text::Bold(name), Ui::Text::WithEntities), - .confirm = ((type == Ui::UserpicButton::ChosenType::Suggest) + .confirm = ((type == ChosenType::Suggest) ? tr::lng_profile_suggest_button(tr::now) : tr::lng_profile_set_photo_button(tr::now)), .cropType = Editor::EditorData::CropType::Ellipse, @@ -1032,7 +1057,7 @@ void TopBar::setupUserpicButton( }; }; - const auto chooseFile = [=](Ui::UserpicButton::ChosenType type) { + const auto chooseFile = [=](ChosenType type) { base::call_delayed( st::defaultRippleAnimation.hideDuration, crl::guard(this, [=] { @@ -1046,7 +1071,7 @@ void TopBar::setupUserpicButton( const auto addFromClipboard = [=]( Ui::PopupMenu *menu, - Ui::UserpicButton::ChosenType type, + ChosenType type, tr::phrase<> text) { if (const auto data = QGuiApplication::clipboard()->mimeData()) { if (data->hasImage()) { @@ -1068,9 +1093,7 @@ void TopBar::setupUserpicButton( _userpicButton->clicks() | rpl::start_with_next([=]( Qt::MouseButton button) { - if (button == Qt::RightButton - && (_hasStories || canReport() || isContact()) - && _peer->userpicPhotoId()) { + if (button == Qt::RightButton && hasMenu()) { *menu = base::make_unique_q( this, st::popupMenuWithIcons); @@ -1095,32 +1118,48 @@ void TopBar::setupUserpicButton( &st::menuIconReport); } - if (isContact()) { + if (canChangePhoto()) { if (!(*menu)->empty()) { (*menu)->addSeparator(&st::expandedMenuSeparator); } - (*menu)->addAction( - tr::lng_profile_set_photo_for(tr::now), - [=] { chooseFile(Ui::UserpicButton::ChosenType::Set); }, - &st::menuIconPhotoSet); - addFromClipboard( - menu->get(), - Ui::UserpicButton::ChosenType::Set, - tr::lng_profile_set_photo_for_from_clipboard); - if (canSuggestPhoto()) { + const auto isUser = _peer->asUser(); + if (isUser) { (*menu)->addAction( - tr::lng_profile_suggest_photo(tr::now), - [=] { - chooseFile( - Ui::UserpicButton::ChosenType::Suggest); - }, - &st::menuIconPhotoSuggest); + tr::lng_profile_set_photo_for(tr::now), + [=] { chooseFile(ChosenType::Set); }, + &st::menuIconPhotoSet); addFromClipboard( menu->get(), - Ui::UserpicButton::ChosenType::Suggest, - tr::lng_profile_suggest_photo_from_clipboard); + ChosenType::Set, + tr::lng_profile_set_photo_for_from_clipboard); + if (canSuggestPhoto()) { + (*menu)->addAction( + tr::lng_profile_suggest_photo(tr::now), + [=] { + chooseFile( + ChosenType::Suggest); + }, + &st::menuIconPhotoSuggest); + addFromClipboard( + menu->get(), + ChosenType::Suggest, + tr::lng_profile_suggest_photo_from_clipboard); + } + } else { + const auto channel = _peer->asChannel(); + const auto isChannel = channel && !channel->isMegagroup(); + (*menu)->addAction( + isChannel + ? tr::lng_profile_set_photo_for_channel(tr::now) + : tr::lng_profile_set_photo_for_group(tr::now), + [=] { chooseFile(ChosenType::Set); }, + &st::menuIconPhotoSet); + addFromClipboard( + menu->get(), + ChosenType::Set, + tr::lng_profile_set_photo_for_from_clipboard); } - if (controller) { + if (controller && isUser) { const auto done = [=](UserpicBuilder::Result data) { auto result = Api::PeerPhoto::UserPhoto{ base::take(data.image),