Display date of birth in user profiles.

This commit is contained in:
John Preston 2024-03-22 19:12:11 +04:00
parent c82d7bd909
commit 08ee25deb2
10 changed files with 166 additions and 22 deletions

View file

@ -1329,6 +1329,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_info_mobile_hidden" = "Hidden";
"lng_info_username_label" = "Username";
"lng_info_usernames_label" = "also";
"lng_info_birthday_label" = "Date of birth";
"lng_info_birthday_years#one" = "{date} ({count} year old)";
"lng_info_birthday_years#other" = "{date} ({count} years old)";
"lng_info_birthday_today_label" = "Birthday today";
"lng_info_birthday_today" = "{emoji} {date}";
"lng_info_bio_label" = "Bio";
"lng_info_link_label" = "Link";
"lng_info_location_label" = "Location";

View file

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_utilities.h"
#include "ui/painter.h"
#include "info/profile/info_profile_text.h"
#include "info/profile/info_profile_values.h"
#include "media/streaming/media_streaming_instance.h"
#include "media/streaming/media_streaming_player.h"
#include "base/event_filter.h"
@ -788,6 +789,10 @@ void PeerShortInfoBox::prepareRows() {
tr::lng_info_username_label(),
usernameValue() | Ui::Text::ToWithEntities(),
tr::lng_context_copy_mention(tr::now));
addInfoOneLine(
birthdayLabel(),
birthdayValue() | Ui::Text::ToWithEntities(),
tr::lng_mediaview_copy(tr::now));
}
RectParts PeerShortInfoBox::customCornersFilling() {
@ -827,29 +832,47 @@ void PeerShortInfoBox::refreshRoundedTopImage(const QColor &color) {
}
rpl::producer<QString> PeerShortInfoBox::nameValue() const {
return _fields.value() | rpl::map([](const PeerShortInfoFields &fields) {
return _fields.value(
) | rpl::map([](const PeerShortInfoFields &fields) {
return fields.name;
}) | rpl::distinct_until_changed();
}
rpl::producer<TextWithEntities> PeerShortInfoBox::linkValue() const {
return _fields.value() | rpl::map([](const PeerShortInfoFields &fields) {
return _fields.value(
) | rpl::map([](const PeerShortInfoFields &fields) {
return Ui::Text::Link(fields.link, fields.link);
}) | rpl::distinct_until_changed();
}
rpl::producer<QString> PeerShortInfoBox::phoneValue() const {
return _fields.value() | rpl::map([](const PeerShortInfoFields &fields) {
return _fields.value(
) | rpl::map([](const PeerShortInfoFields &fields) {
return fields.phone;
}) | rpl::distinct_until_changed();
}
rpl::producer<QString> PeerShortInfoBox::usernameValue() const {
return _fields.value() | rpl::map([](const PeerShortInfoFields &fields) {
return _fields.value(
) | rpl::map([](const PeerShortInfoFields &fields) {
return fields.username;
}) | rpl::distinct_until_changed();
}
rpl::producer<QString> PeerShortInfoBox::birthdayLabel() const {
return Info::Profile::BirthdayLabelText(_fields.value(
) | rpl::map([](const PeerShortInfoFields &fields) {
return fields.birthday;
}) | rpl::distinct_until_changed());
}
rpl::producer<QString> PeerShortInfoBox::birthdayValue() const {
return Info::Profile::BirthdayValueText(_fields.value(
) | rpl::map([](const PeerShortInfoFields &fields) {
return fields.birthday;
}) | rpl::distinct_until_changed());
}
rpl::producer<TextWithEntities> PeerShortInfoBox::aboutValue() const {
return _fields.value() | rpl::map([](const PeerShortInfoFields &fields) {
return fields.about;

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "data/data_birthday.h"
#include "ui/layers/box_content.h"
namespace style {
@ -40,6 +41,7 @@ struct PeerShortInfoFields {
QString link;
TextWithEntities about;
QString username;
Data::Birthday birthday;
bool isBio = false;
};
@ -171,6 +173,8 @@ private:
[[nodiscard]] rpl::producer<TextWithEntities> linkValue() const;
[[nodiscard]] rpl::producer<QString> phoneValue() const;
[[nodiscard]] rpl::producer<QString> usernameValue() const;
[[nodiscard]] rpl::producer<QString> birthdayLabel() const;
[[nodiscard]] rpl::producer<QString> birthdayValue() const;
[[nodiscard]] rpl::producer<TextWithEntities> aboutValue() const;
const style::ShortInfoBox &_st;

View file

@ -203,7 +203,8 @@ void ProcessFullPhoto(
(UpdateFlag::Name
| UpdateFlag::PhoneNumber
| UpdateFlag::Username
| UpdateFlag::About)
| UpdateFlag::About
| UpdateFlag::Birthday)
) | rpl::map([=] {
const auto user = peer->asUser();
const auto username = peer->userName();
@ -217,6 +218,7 @@ void ProcessFullPhoto(
.username = ((user && !username.isEmpty())
? ('@' + username)
: QString()),
.birthday = user ? user->birthday() : Data::Birthday(),
.isBio = (user && !user->isBot()),
};
});

View file

@ -7,6 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "data/data_birthday.h"
#include "base/timer_rpl.h"
#include "lang/lang_keys.h"
#include <QtCore/QDate>
namespace Data {
namespace {
@ -66,5 +71,62 @@ int Birthday::year() const {
return _value / 10000;
}
QString BirthdayText(Birthday date) {
if (const auto year = date.year()) {
return tr::lng_month_day_year(
tr::now,
lt_month,
Lang::MonthSmall(date.month())(tr::now),
lt_day,
QString::number(date.day()),
lt_year,
QString::number(year));
} else if (date) {
return tr::lng_month_day(
tr::now,
lt_month,
Lang::MonthSmall(date.month())(tr::now),
lt_day,
QString::number(date.day()));
}
return QString();
}
QString BirthdayCake() {
return QString::fromUtf8("\xf0\x9f\x8e\x82");
}
int BirthdayAge(Birthday date) {
if (!date.year()) {
return 0;
}
const auto now = QDate::currentDate();
const auto day = QDate(date.year(), date.month(), date.day());
if (!day.isValid() || day >= now) {
return 0;
}
auto age = now.year() - date.year();
if (now < QDate(date.year() + age, date.month(), date.day())) {
--age;
}
return age;
}
bool IsBirthdayToday(Birthday date) {
if (!date) {
return false;
}
const auto now = QDate::currentDate();
return date.day() == now.day() && date.month() == now.month();
}
rpl::producer<bool> IsBirthdayTodayValue(Birthday date) {
return rpl::single() | rpl::then(base::timer_each(
60 * crl::time(1000)
)) | rpl::map([=] {
return IsBirthdayToday(date);
}) | rpl::distinct_until_changed();
}
} // namespace Data

View file

@ -38,4 +38,10 @@ private:
};
[[nodiscard]] QString BirthdayText(Birthday date);
[[nodiscard]] QString BirthdayCake();
[[nodiscard]] int BirthdayAge(Birthday date);
[[nodiscard]] bool IsBirthdayToday(Birthday date);
[[nodiscard]] rpl::producer<bool> IsBirthdayTodayValue(Birthday date);
} // namespace Data

View file

@ -1003,6 +1003,14 @@ object_ptr<Ui::RpWidget> DetailsFiller::setupInfo() {
return false;
});
} else {
addInfoOneLine(
BirthdayLabelText(BirthdayValue(user)),
BirthdayValueText(
BirthdayValue(user)
) | Ui::Text::ToWithEntities(),
tr::lng_mediaview_copy(tr::now),
st::infoProfileLabeledUsernamePadding);
tracker.track(result->add(CreateWorkingHours(result, user)));
auto locationText = user->session().changes().peerFlagsValue(

View file

@ -635,5 +635,48 @@ rpl::producer<DocumentId> EmojiStatusIdValue(not_null<PeerData*> peer) {
) | rpl::map([=] { return peer->emojiStatusId(); });
}
rpl::producer<QString> BirthdayLabelText(
rpl::producer<Data::Birthday> birthday) {
return std::move(birthday) | rpl::map([](Data::Birthday value) {
return rpl::conditional(
Data::IsBirthdayTodayValue(value),
tr::lng_info_birthday_today_label(),
tr::lng_info_birthday_label());
}) | rpl::flatten_latest();
}
rpl::producer<QString> BirthdayValueText(
rpl::producer<Data::Birthday> birthday) {
return std::move(
birthday
) | rpl::map([](Data::Birthday value) -> rpl::producer<QString> {
if (!value) {
return rpl::single(QString());
}
return Data::IsBirthdayTodayValue(
value
) | rpl::map([=](bool today) {
auto text = Data::BirthdayText(value);
if (const auto age = Data::BirthdayAge(value)) {
text = tr::lng_info_birthday_years(
tr::now,
lt_count,
age,
lt_date,
text);
}
if (today) {
text = tr::lng_info_birthday_today(
tr::now,
lt_emoji,
Data::BirthdayCake(),
lt_date,
text);
}
return text;
});
}) | rpl::flatten_latest();
}
} // namespace Profile
} // namespace Info

View file

@ -121,4 +121,9 @@ enum class BadgeType;
[[nodiscard]] rpl::producer<DocumentId> EmojiStatusIdValue(
not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<QString> BirthdayLabelText(
rpl::producer<Data::Birthday> birthday);
[[nodiscard]] rpl::producer<QString> BirthdayValueText(
rpl::producer<Data::Birthday> birthday);
} // namespace Info::Profile

View file

@ -367,23 +367,9 @@ void SetupBirthday(
Info::Profile::BirthdayValue(self),
tr::lng_settings_birthday_add()
) | rpl::map([](Data::Birthday birthday, const QString &add) {
const auto wrap = &Ui::Text::WithEntities;
if (const auto year = birthday.year()) {
return wrap(tr::lng_month_day_year(
tr::now,
lt_month,
Lang::MonthSmall(birthday.month())(tr::now),
lt_day,
QString::number(birthday.day()),
lt_year,
QString::number(year)));
} else if (birthday) {
return wrap(tr::lng_month_day(
tr::now,
lt_month,
Lang::MonthSmall(birthday.month())(tr::now),
lt_day,
QString::number(birthday.day())));
const auto text = Data::BirthdayText(birthday);
if (!text.isEmpty()) {
return TextWithEntities{ text };
}
auto result = TextWithEntities{ add };
result.entities.push_back({