Added ability to manage contact photo in edit contact box.

This commit is contained in:
23rd
2025-09-21 09:55:31 +03:00
committed by John Preston
parent 44faef3027
commit 0decf928f0
3 changed files with 230 additions and 1 deletions
+4
View File
@@ -1642,6 +1642,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_set_photo_for_from_clipboard" = "Set From Clipboard"; "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_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"; "lng_profile_photo_reset" = "Reset to Original";
"lng_profile_photo_reset_sure" = "Are you sure you want to reset {user}'s photo to the original?";
"lng_profile_photo_from_clipboard" = "From clipboard"; "lng_profile_photo_from_clipboard" = "From clipboard";
"lng_profile_suggest_sure" = "You can suggest {user} to set this photo for their Telegram profile."; "lng_profile_suggest_sure" = "You can suggest {user} to set this photo for their Telegram profile.";
"lng_profile_suggest_button" = "Suggest"; "lng_profile_suggest_button" = "Suggest";
@@ -4798,6 +4799,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_contact_phone_will_be_shared" = "You can make your phone visible to {user}."; "lng_contact_phone_will_be_shared" = "You can make your phone visible to {user}.";
"lng_contact_add_notes" = "Note"; "lng_contact_add_notes" = "Note";
"lng_contact_add_notes_about" = "Notes are only visible to you."; "lng_contact_add_notes_about" = "Notes are only visible to you.";
"lng_suggest_photo_for" = "Suggest Photo for {user}";
"lng_set_photo_for_user" = "Set Photo for {user}";
"lng_contact_photo_replace_info" = "You can replace {user}'s photo with another photo that only you will see.";
"lng_edit_contact_title" = "Edit contact"; "lng_edit_contact_title" = "Edit contact";
"lng_edit_channel_title" = "Edit channel"; "lng_edit_channel_title" = "Edit channel";
"lng_edit_bot_title" = "Edit bot"; "lng_edit_bot_title" = "Edit bot";
@@ -14,18 +14,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/tabbed_panel.h" #include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h" #include "chat_helpers/tabbed_selector.h"
#include "core/ui_integration.h" #include "core/ui_integration.h"
#include "data/data_changes.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_premium_limits.h" #include "data/data_premium_limits.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/stickers/data_custom_emoji.h" #include "data/stickers/data_custom_emoji.h"
#include "data/stickers/data_stickers.h" #include "data/stickers/data_stickers.h"
#include "editor/photo_editor_common.h"
#include "editor/photo_editor_layer_widget.h"
#include "history/view/controls/history_view_characters_limit.h" #include "history/view/controls/history_view_characters_limit.h"
#include "info/profile/info_profile_cover.h" #include "info/profile/info_profile_cover.h"
#include "info/userpic/info_userpic_emoji_builder_common.h"
#include "info/userpic/info_userpic_emoji_builder_menu_item.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "settings/settings_common.h"
#include "ui/controls/emoji_button_factory.h" #include "ui/controls/emoji_button_factory.h"
#include "ui/controls/emoji_button.h" #include "ui/controls/emoji_button.h"
#include "ui/controls/userpic_button.h"
#include "ui/boxes/confirm_box.h"
#include "ui/text/format_values.h" // Ui::FormatPhone #include "ui/text/format_values.h" // Ui::FormatPhone
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
@@ -33,6 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/fields/input_field.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/popup_menu.h"
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
#include "window/window_controller.h" #include "window/window_controller.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
@@ -40,6 +49,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_chat_helpers.h" #include "styles/style_chat_helpers.h"
#include "styles/style_info.h" #include "styles/style_info.h"
#include "styles/style_layers.h" #include "styles/style_layers.h"
#include "styles/style_menu_icons.h"
#include "styles/style_settings.h"
#include <QtGui/QClipboard>
#include <QtGui/QGuiApplication>
namespace { namespace {
@@ -107,19 +121,28 @@ private:
void setupCover(); void setupCover();
void setupNameFields(); void setupNameFields();
void setupNotesField(); void setupNotesField();
void setupPhotoButtons();
void setupWarning(); void setupWarning();
void setupSharePhoneNumber(); void setupSharePhoneNumber();
void initNameFields( void initNameFields(
not_null<Ui::InputField*> first, not_null<Ui::InputField*> first,
not_null<Ui::InputField*> last, not_null<Ui::InputField*> last,
bool inverted); bool inverted);
void showPhotoMenu(bool suggest);
void choosePhotoFile(bool suggest);
void processChosenPhoto(QImage &&image, bool suggest);
void processChosenPhotoWithMarkup(
UserpicBuilder::Result &&data,
bool suggest);
not_null<Ui::GenericBox*> _box; not_null<Ui::GenericBox*> _box;
not_null<Window::SessionController*> _window; not_null<Window::SessionController*> _window;
not_null<UserData*> _user; not_null<UserData*> _user;
Ui::Checkbox *_sharePhone = nullptr; Ui::Checkbox *_sharePhone = nullptr;
Ui::InputField *_notesField = nullptr; Ui::InputField *_notesField = nullptr;
Ui::InputField *_firstNameField = nullptr;
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel; base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
base::unique_qptr<Ui::PopupMenu> _photoMenu;
QString _phone; QString _phone;
Fn<void()> _focus; Fn<void()> _focus;
Fn<void()> _save; Fn<void()> _save;
@@ -153,6 +176,7 @@ void Controller::setupContent() {
setupCover(); setupCover();
setupNameFields(); setupNameFields();
setupNotesField(); setupNotesField();
setupPhotoButtons();
setupWarning(); setupWarning();
setupSharePhoneNumber(); setupSharePhoneNumber();
} }
@@ -173,13 +197,14 @@ void Controller::setupCover() {
void Controller::setupNameFields() { void Controller::setupNameFields() {
const auto inverted = langFirstNameGoesSecond(); const auto inverted = langFirstNameGoesSecond();
const auto first = _box->addRow( _firstNameField = _box->addRow(
object_ptr<Ui::InputField>( object_ptr<Ui::InputField>(
_box, _box,
st::defaultInputField, st::defaultInputField,
tr::lng_signup_firstname(), tr::lng_signup_firstname(),
_user->firstName), _user->firstName),
st::addContactFieldMargin); st::addContactFieldMargin);
const auto first = _firstNameField;
auto preparedLast = object_ptr<Ui::InputField>( auto preparedLast = object_ptr<Ui::InputField>(
_box, _box,
st::defaultInputField, st::defaultInputField,
@@ -393,6 +418,91 @@ void Controller::setupNotesField() {
tr::lng_contact_add_notes_about()); tr::lng_contact_add_notes_about());
} }
void Controller::setupPhotoButtons() {
auto nameValue = _firstNameField
? rpl::merge(
rpl::single(_firstNameField->getLastText().trimmed()),
_firstNameField->changes() | rpl::map([=] {
return _firstNameField->getLastText().trimmed();
})) | rpl::map([=](const QString &text) {
return text.isEmpty() ? Ui::kQEllipsis : text;
})
: rpl::single(_user->shortName());
const auto inner = _box->verticalLayout();
Ui::AddSkip(inner);
const auto suggestButton = Settings::AddButtonWithIcon(
inner,
tr::lng_suggest_photo_for(lt_user, rpl::duplicate(nameValue)),
st::settingsButtonLight,
{ &st::menuBlueIconPhotoSuggest });
suggestButton->setClickedCallback([=] {
showPhotoMenu(true);
});
const auto setButton = Settings::AddButtonWithIcon(
inner,
tr::lng_set_photo_for_user(lt_user, rpl::duplicate(nameValue)),
st::settingsButtonLight,
{ &st::menuBlueIconPhotoSet });
setButton->setClickedCallback([=] {
showPhotoMenu(false);
});
const auto resetButton = Settings::AddButtonWithIcon(
inner,
tr::lng_profile_photo_reset(),
st::settingsButtonLight,
{ nullptr });
const auto userpicButton = Ui::CreateChild<Ui::UserpicButton>(
resetButton,
_window,
_user,
Ui::UserpicButton::Role::Custom,
Ui::UserpicButton::Source::NonPersonalIfHasPersonal,
st::restoreUserpicIcon);
userpicButton->setAttribute(Qt::WA_TransparentForMouseEvents);
resetButton->sizeValue(
) | rpl::start_with_next([=](QSize size) {
userpicButton->move(
st::settingsButtonLight.iconLeft,
(size.height() - userpicButton->height()) / 2);
}, userpicButton->lifetime());
_user->session().changes().peerFlagsValue(
_user,
Data::PeerUpdate::Flag::FullInfo
) | rpl::map([=] {
return _user->hasPersonalPhoto();
}) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](bool hasPersonal) {
resetButton->setVisible(hasPersonal);
}, resetButton->lifetime());
resetButton->setVisible(_user->hasPersonalPhoto());
resetButton->setClickedCallback([=] {
_window->show(Ui::MakeConfirmBox({
.text = tr::lng_profile_photo_reset_sure(
tr::now,
lt_user,
_user->shortName()),
.confirmed = [=] {
_window->session().api().peerPhoto().clearPersonal(_user);
},
.confirmText = tr::lng_profile_photo_reset(tr::now),
}));
});
Ui::AddSkip(inner);
Ui::AddDividerText(
inner,
tr::lng_contact_photo_replace_info(lt_user, std::move(nameValue)));
}
void Controller::setupSharePhoneNumber() { void Controller::setupSharePhoneNumber() {
const auto settings = _user->barSettings(); const auto settings = _user->barSettings();
if (!settings if (!settings
@@ -415,6 +525,120 @@ void Controller::setupSharePhoneNumber() {
} }
void Controller::showPhotoMenu(bool suggest) {
_photoMenu = base::make_unique_q<Ui::PopupMenu>(
_box,
st::popupMenuWithIcons);
_photoMenu->addAction(
tr::lng_attach_photo(tr::now),
[=] { choosePhotoFile(suggest); },
&st::menuIconPhoto);
if (const auto data = QGuiApplication::clipboard()->mimeData()) {
if (data->hasImage()) {
auto callback = [=] {
Editor::PrepareProfilePhoto(
_box,
&_window->window(),
Editor::EditorData{
.about = (suggest
? tr::lng_profile_suggest_sure(
tr::now,
lt_user,
Ui::Text::Bold(_user->shortName()),
Ui::Text::WithEntities)
: tr::lng_profile_set_personal_sure(
tr::now,
lt_user,
Ui::Text::Bold(_user->shortName()),
Ui::Text::WithEntities)),
.confirm = (suggest
? tr::lng_profile_suggest_button(tr::now)
: tr::lng_profile_set_photo_button(tr::now)),
.cropType = Editor::EditorData::CropType::Ellipse,
.keepAspectRatio = true,
},
[=](QImage &&editedImage) {
processChosenPhoto(std::move(editedImage), suggest);
},
qvariant_cast<QImage>(data->imageData()));
};
_photoMenu->addAction(
tr::lng_profile_photo_from_clipboard(tr::now),
std::move(callback),
&st::menuIconPhoto);
}
}
UserpicBuilder::AddEmojiBuilderAction(
_window,
_photoMenu.get(),
_window->session().api().peerPhoto().emojiListValue(
Api::PeerPhoto::EmojiListType::Profile),
[=](UserpicBuilder::Result data) {
processChosenPhotoWithMarkup(std::move(data), suggest);
},
false);
_photoMenu->popup(QCursor::pos());
}
void Controller::choosePhotoFile(bool suggest) {
Editor::PrepareProfilePhotoFromFile(
_box,
&_window->window(),
Editor::EditorData{
.about = (suggest
? tr::lng_profile_suggest_sure(
tr::now,
lt_user,
Ui::Text::Bold(_user->shortName()),
Ui::Text::WithEntities)
: tr::lng_profile_set_personal_sure(
tr::now,
lt_user,
Ui::Text::Bold(_user->shortName()),
Ui::Text::WithEntities)),
.confirm = (suggest
? tr::lng_profile_suggest_button(tr::now)
: tr::lng_profile_set_photo_button(tr::now)),
.cropType = Editor::EditorData::CropType::Ellipse,
.keepAspectRatio = true,
},
[=](QImage &&image) {
processChosenPhoto(std::move(image), suggest);
});
}
void Controller::processChosenPhoto(QImage &&image, bool suggest) {
Api::PeerPhoto::UserPhoto photo{
.image = base::duplicate(image),
};
if (suggest) {
_window->session().api().peerPhoto().suggest(_user, std::move(photo));
_window->showPeerHistory(_user->id);
} else {
_window->session().api().peerPhoto().upload(_user, std::move(photo));
}
}
void Controller::processChosenPhotoWithMarkup(
UserpicBuilder::Result &&data,
bool suggest) {
Api::PeerPhoto::UserPhoto photo{
.image = std::move(data.image),
.markupDocumentId = data.id,
.markupColors = std::move(data.colors),
};
if (suggest) {
_window->session().api().peerPhoto().suggest(_user, std::move(photo));
_window->showPeerHistory(_user->id);
} else {
_window->session().api().peerPhoto().upload(_user, std::move(photo));
}
}
} // namespace } // namespace
void EditContactBox( void EditContactBox(
+1
View File
@@ -200,6 +200,7 @@ menuIconMuteForAnyTextPosition: point(14px, 9px);
menuIconMuteForAnyTextFont: font(8px semibold); menuIconMuteForAnyTextFont: font(8px semibold);
menuBlueIconPhotoSet: icon {{ "menu/photo_set", lightButtonFg }}; menuBlueIconPhotoSet: icon {{ "menu/photo_set", lightButtonFg }};
menuBlueIconPhotoSuggest: icon {{ "menu/photo_suggest", lightButtonFg }};
menuBlueIconPremium: icon{{ "menu/premium", lightButtonFg }}; menuBlueIconPremium: icon{{ "menu/premium", lightButtonFg }};
menuBlueIconColorNames: icon{{ "settings/premium/features/feature_color_names", lightButtonFg }}; menuBlueIconColorNames: icon{{ "settings/premium/features/feature_color_names", lightButtonFg }};
menuBlueIconWallpaper: icon{{ "settings/premium/features/feature_wallpaper", lightButtonFg }}; menuBlueIconWallpaper: icon{{ "settings/premium/features/feature_wallpaper", lightButtonFg }};