Improved birthday reminder of multiple contacts in top bar from dialogs.

This commit is contained in:
23rd 2025-04-08 00:34:53 +03:00 committed by John Preston
parent dc1dc8dffa
commit 423782fd2b
3 changed files with 49 additions and 44 deletions

View file

@ -3870,6 +3870,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_dialogs_suggestions_birthday_contacts_title#one" = "{count} contact have **birthdays** today! 🎂"; "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_title#other" = "{count} contacts have **birthdays** today! 🎂";
"lng_dialogs_suggestions_birthday_contacts_about" = "Send them a Gift."; "lng_dialogs_suggestions_birthday_contacts_about" = "Send them a Gift.";
"lng_dialogs_suggestions_birthday_contact_dismiss" = "You can send a Gift later in Settings";
"lng_dialogs_suggestions_premium_annual_title" = "Telegram Premium with a {text} discount"; "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_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"; "lng_dialogs_suggestions_premium_upgrade_title" = "Telegram Premium with a {text} discount";

View file

@ -52,31 +52,6 @@ constexpr auto kSugPremiumUpgrade = "PREMIUM_UPGRADE"_cs;
constexpr auto kSugPremiumRestore = "PREMIUM_RESTORE"_cs; constexpr auto kSugPremiumRestore = "PREMIUM_RESTORE"_cs;
constexpr auto kSugSetUserpic = "USERPIC_SETUP"_cs; constexpr auto kSugSetUserpic = "USERPIC_SETUP"_cs;
void RequestBirthdays(
not_null<PeerData*> peer,
Fn<void(std::vector<not_null<PeerData*>>)> done) {
peer->session().api().request(
MTPcontacts_GetBirthdays()
).done([=](const MTPcontacts_ContactBirthdays &result) {
auto users = std::vector<not_null<PeerData*>>();
peer->owner().processUsers(result.data().vusers());
for (const auto &tlContact : result.data().vcontacts().v) {
const auto peerId = tlContact.data().vcontact_id().v;
if (const auto user = peer->owner().user(peerId)) {
const auto &data = tlContact.data().vbirthday().data();
user->setBirthday(Data::Birthday(
data.vday().v,
data.vmonth().v,
data.vyear().value_or_empty()));
users.push_back(user);
}
}
done(std::move(users));
}).fail([=](const MTP::Error &error) {
done({});
}).send();
}
} // namespace } // namespace
rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue( rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
@ -120,39 +95,43 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
const auto wrap = state->wrap; const auto wrap = state->wrap;
using RightIcon = TopBarSuggestionContent::RightIcon; using RightIcon = TopBarSuggestionContent::RightIcon;
const auto config = &session->appConfig(); const auto config = &session->appConfig();
if (config->suggestionCurrent(kSugBirthdayContacts.utf8())) { if (session->premiumCanBuy()
using Users = std::vector<not_null<PeerData*>>; && config->suggestionCurrent(kSugBirthdayContacts.utf8())) {
RequestBirthdays(session->user(), crl::guard(content, [=]( session->data().contactBirthdays(
Users users) { ) | rpl::start_with_next(crl::guard(content, [=](
const auto dismiss = [=] { std::vector<UserId> users) {
config->dismissSuggestion( if (users.empty()) {
kSugBirthdayContacts.utf8());
repeat(repeat); repeat(repeat);
};
if (!session->premiumCanBuy() || users.empty()) {
dismiss();
return; return;
} }
const auto controller = FindSessionController(parent); const auto controller = FindSessionController(parent);
if (!controller || users.empty()) { if (!controller) {
dismiss(); repeat(repeat);
return; return;
} }
const auto isSingle = users.size() == 1; const auto isSingle = users.size() == 1;
const auto first = session->data().user(users.front());
content->setRightIcon(RightIcon::Close); content->setRightIcon(RightIcon::Close);
content->setClickedCallback([=] { content->setClickedCallback([=] {
if (isSingle) { if (isSingle) {
Ui::ShowStarGiftBox(controller, users.front()); Ui::ShowStarGiftBox(controller, first);
} else { } else {
Ui::ChooseStarGiftRecipient(controller); Ui::ChooseStarGiftRecipient(controller);
} }
}); });
content->setHideCallback(dismiss); content->setHideCallback([=] {
config->dismissSuggestion(
kSugBirthdayContacts.utf8());
controller->showToast(
tr::lng_dialogs_suggestions_birthday_contact_dismiss(
tr::now));
repeat(repeat);
});
auto title = isSingle auto title = isSingle
? tr::lng_dialogs_suggestions_birthday_contact_title( ? tr::lng_dialogs_suggestions_birthday_contact_title(
tr::now, tr::now,
lt_text, lt_text,
{ users.front()->name() }, { first->name() },
Ui::Text::RichLangValue) Ui::Text::RichLangValue)
: tr::lng_dialogs_suggestions_birthday_contacts_title( : tr::lng_dialogs_suggestions_birthday_contacts_title(
tr::now, tr::now,
@ -188,8 +167,10 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
widget->show(); widget->show();
widget->raise(); widget->raise();
}, widget->lifetime()); }, widget->lifetime());
for (const auto &user : users) { for (const auto &id : users) {
s->inRow.push_back({ .peer = user }); if (const auto user = session->data().user(id)) {
s->inRow.push_back({ .peer = user });
}
} }
widget->paintRequest() | rpl::start_with_next([=] { widget->paintRequest() | rpl::start_with_next([=] {
auto p = QPainter(widget); auto p = QPainter(widget);
@ -229,7 +210,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
= state->giftsLifetime.template make_state<Ptr>( = state->giftsLifetime.template make_state<Ptr>(
base::make_unique_q<Ui::UserpicButton>( base::make_unique_q<Ui::UserpicButton>(
content, content,
users.front(), first,
st::uploadUserpicButton)); st::uploadUserpicButton));
const auto fake = ptr->get(); const auto fake = ptr->get();
fake->setAttribute(Qt::WA_TransparentForMouseEvents); fake->setAttribute(Qt::WA_TransparentForMouseEvents);
@ -245,7 +226,7 @@ rpl::producer<Ui::SlideWrap<Ui::RpWidget>*> TopBarSuggestionValue(
} }
wrap->toggle(true, anim::type::normal); wrap->toggle(true, anim::type::normal);
})); }), state->giftsLifetime);
return; return;
} else if (config->suggestionCurrent(kSugSetBirthday.utf8()) } else if (config->suggestionCurrent(kSugSetBirthday.utf8())
&& !Data::IsBirthdayToday(session->user()->birthday())) { && !Data::IsBirthdayToday(session->user()->birthday())) {

View file

@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h" #include "apiwrap.h"
#include "base/call_delayed.h" #include "base/call_delayed.h"
#include "main/main_account.h" #include "main/main_account.h"
#include "main/main_session.h"
#include "data/data_session.h"
#include "ui/chat/chat_style.h" #include "ui/chat/chat_style.h"
namespace Main { namespace Main {
@ -136,6 +138,15 @@ void AppConfig::refresh(bool force) {
} }
updateIgnoredRestrictionReasons(std::move(was)); updateIgnoredRestrictionReasons(std::move(was));
{
const auto dismissedSuggestions = get<std::vector<QString>>(
u"dismissed_suggestions"_q,
std::vector<QString>());
for (const auto &suggestion : dismissedSuggestions) {
_dismissedSuggestions.emplace(suggestion);
}
}
DEBUG_LOG(("getAppConfig result handled.")); DEBUG_LOG(("getAppConfig result handled."));
_refreshed.fire({}); _refreshed.fire({});
}, [](const MTPDhelp_appConfigNotModified &) {}); }, [](const MTPDhelp_appConfigNotModified &) {});
@ -289,6 +300,18 @@ std::vector<int> AppConfig::getIntArray(
} }
bool AppConfig::suggestionCurrent(const QString &key) const { bool AppConfig::suggestionCurrent(const QString &key) const {
if (key == u"BIRTHDAY_CONTACTS_TODAY"_q) {
if (_dismissedSuggestions.contains(key)) {
return false;
} else {
const auto known
= _account->session().data().knownContactBirthdays();
if (!known) {
return true;
}
return !known->empty();
}
}
return !_dismissedSuggestions.contains(key) return !_dismissedSuggestions.contains(key)
&& ranges::contains( && ranges::contains(
get<std::vector<QString>>( get<std::vector<QString>>(