From 8c0de22c149ce37c5fef25ce38d06dc7f2299466 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 7 Apr 2025 00:40:34 +0300 Subject: [PATCH] Added birthday reminder of multiple contacts to top bar in dialogs. --- Telegram/Resources/langs/lang.strings | 3 + .../dialogs/dialogs_top_bar_suggestion.cpp | 128 ++++++++++++++---- 2 files changed, 106 insertions(+), 25 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index e1fdf3dcbf..0315896bff 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3867,6 +3867,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_dialogs_suggestions_birthday_about" = "Let your contacts know when youโ€™re celebrating."; "lng_dialogs_suggestions_birthday_contact_title" = "Itโ€™s {text}'s **birthday** today! ๐ŸŽ‚"; "lng_dialogs_suggestions_birthday_contact_about" = "Send them a Gift."; +"lng_dialogs_suggestions_birthday_contacts_title#one" = "{count} contact have **birthdays** today! ๐ŸŽ‚"; +"lng_dialogs_suggestions_birthday_contacts_title#other" = "{count} contacts have **birthdays** today! ๐ŸŽ‚"; +"lng_dialogs_suggestions_birthday_contacts_about" = "Send them a Gift."; "lng_dialogs_suggestions_premium_annual_title" = "Telegram Premium with a {text} discount"; "lng_dialogs_suggestions_premium_annual_about" = "Sign up for the annual payment plan for Telegram Premium now to get the discount."; "lng_dialogs_suggestions_premium_upgrade_title" = "Telegram Premium with a {text} discount"; diff --git a/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp b/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp index 1b489ffd07..1697dd9eb6 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_user.h" #include "dialogs/ui/dialogs_top_bar_suggestion_content.h" +#include "history/view/history_view_group_call_bar.h" #include "info/profile/info_profile_values.h" #include "lang/lang_keys.h" #include "main/main_app_config.h" @@ -31,6 +32,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_controller.h" #include "window/window_session_controller.h" #include "styles/style_boxes.h" +#include "styles/style_chat.h" +#include "styles/style_chat_helpers.h" #include "styles/style_dialogs.h" namespace Dialogs { @@ -88,7 +91,9 @@ rpl::producer*> TopBarSuggestionValue( rpl::lifetime birthdayLifetime; rpl::lifetime premiumLifetime; rpl::lifetime userpicLifetime; + rpl::lifetime giftsLifetime; }; + const auto state = lifetime.make_state(); const auto ensureWrap = [=] { if (!state->content) { @@ -129,42 +134,115 @@ rpl::producer*> TopBarSuggestionValue( return; } const auto controller = FindSessionController(parent); - if (!controller) { + if (!controller || users.empty()) { dismiss(); return; } - if (users.size() != 1) { - return; - } + const auto isSingle = users.size() == 1; content->setRightIcon(RightIcon::Close); content->setClickedCallback([=] { - Ui::ShowStarGiftBox(controller, users.front()); + if (isSingle) { + Ui::ShowStarGiftBox(controller, users.front()); + } else { + Ui::ChooseStarGiftRecipient(controller); + } }); content->setHideCallback(dismiss); - content->setContent( - tr::lng_dialogs_suggestions_birthday_contact_title( + auto title = isSingle + ? tr::lng_dialogs_suggestions_birthday_contact_title( tr::now, lt_text, { users.front()->name() }, - Ui::Text::RichLangValue), - tr::lng_dialogs_suggestions_birthday_contact_about( + Ui::Text::RichLangValue) + : tr::lng_dialogs_suggestions_birthday_contacts_title( tr::now, - TextWithEntities::Simple)); - const auto upload = Ui::CreateChild( - content, - users.front(), - st::uploadUserpicButton); - upload->setAttribute(Qt::WA_TransparentForMouseEvents); - const auto leftPadding = st::defaultDialogRow.padding.left(); - content->sizeValue() | rpl::filter_size( - ) | rpl::start_with_next([=](const QSize &s) { - upload->raise(); - upload->show(); - upload->moveToLeft( - leftPadding, - (s.height() - upload->height()) / 2); - }, content->lifetime()); - content->setLeftPadding(upload->width() + leftPadding); + lt_count, + users.size(), + Ui::Text::RichLangValue); + auto text = isSingle + ? tr::lng_dialogs_suggestions_birthday_contact_about( + tr::now, + TextWithEntities::Simple) + : tr::lng_dialogs_suggestions_birthday_contacts_about( + tr::now, + TextWithEntities::Simple); + content->setContent(std::move(title), std::move(text)); + const auto leftPadding + = st::defaultDialogRow.padding.left(); + state->giftsLifetime.destroy(); + if (!isSingle) { + struct UserViews { + std::vector inRow; + QImage userpics; + base::unique_qptr widget; + }; + const auto s + = state->giftsLifetime.template make_state< + UserViews>(); + s->widget = base::make_unique_q( + content); + const auto widget = s->widget.get(); + content->sizeValue() | rpl::filter_size( + ) | rpl::start_with_next([=](const QSize &size) { + widget->resize(size); + widget->show(); + widget->raise(); + }, widget->lifetime()); + for (const auto &user : users) { + s->inRow.push_back({ .peer = user }); + } + widget->paintRequest() | rpl::start_with_next([=] { + auto p = QPainter(widget); + const auto regenerate = [&] { + if (s->userpics.isNull()) { + return true; + } + for (auto &entry : s->inRow) { + if (entry.uniqueKey + != entry.peer->userpicUniqueKey( + entry.view)) { + return true; + } + } + return false; + }(); + if (regenerate) { + const auto &st = st::historyCommentsUserpics; + HistoryView::GenerateUserpicsInRow( + s->userpics, + s->inRow, + st, + 3); + content->setLeftPadding(leftPadding + + (users.size() * st.size - st.shift)); + } + p.drawImage( + leftPadding, + (widget->height() + - (s->userpics.height() + / style::DevicePixelRatio())) / 2, + s->userpics); + }, widget->lifetime()); + } else { + using Ptr = base::unique_qptr; + const auto ptr + = state->giftsLifetime.template make_state( + base::make_unique_q( + content, + users.front(), + st::uploadUserpicButton)); + const auto fake = ptr->get(); + fake->setAttribute(Qt::WA_TransparentForMouseEvents); + content->sizeValue() | rpl::filter_size( + ) | rpl::start_with_next([=](const QSize &s) { + fake->raise(); + fake->show(); + fake->moveToLeft( + leftPadding, + (s.height() - fake->height()) / 2); + }, content->lifetime()); + content->setLeftPadding(fake->width() + leftPadding); + } wrap->toggle(true, anim::type::normal); }));