From d61c604bf450eedb64ca9d1cf23add073a8de299 Mon Sep 17 00:00:00 2001 From: Zach H Date: Sun, 16 Jan 2022 16:51:13 -0500 Subject: [PATCH] Address macOS issue where right-clicking a username in the main chat (#4523) * Address macOS issue where right-clicking a username in the main chat (or game chat) areas would pop up a seemingly empty user profile. This is because the resize event is overridden and doesn't actually attempt to resize based on the size hint of the dialog. Now that we're explicit with the call, this resize should be forced and have comparable results to popping up user profile from the user list. * use datetime for calculating account age (#4526) * use datetime for calculating account age make translating easier by using tr multiples automatically account for leap days Co-authored-by: ebbit1q --- cockatrice/src/userinfobox.cpp | 60 +++++++++++++++++----------------- cockatrice/src/userinfobox.h | 10 ++++++ tests/CMakeLists.txt | 5 +++ tests/test_age_formatting.cpp | 44 +++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 30 deletions(-) create mode 100644 tests/test_age_formatting.cpp diff --git a/cockatrice/src/userinfobox.cpp b/cockatrice/src/userinfobox.cpp index 61e9965e0..0a7d451b0 100644 --- a/cockatrice/src/userinfobox.cpp +++ b/cockatrice/src/userinfobox.cpp @@ -11,20 +11,15 @@ #include #include -#include #include #include -const qint64 SIXTY = 60; -const qint64 HOURS_IN_A_DAY = 24; -const qint64 DAYS_IN_A_YEAR = 365; - UserInfoBox::UserInfoBox(AbstractClient *_client, bool _editable, QWidget *parent, Qt::WindowFlags flags) : QWidget(parent, flags), client(_client), editable(_editable) { QFont nameFont = nameLabel.font(); nameFont.setBold(true); - nameFont.setPointSize(nameFont.pointSize() * 1.5); + nameFont.setPointSizeF(nameFont.pointSizeF() * 1.5); nameLabel.setFont(nameFont); avatarLabel.setMinimumSize(200, 200); @@ -90,7 +85,6 @@ void UserInfoBox::updateInfo(const ServerInfo_User &user) avatarPixmap = UserLevelPixmapGenerator::generatePixmap(64, userLevel, false, QString::fromStdString(user.privlevel())); } - avatarLabel.setPixmap(avatarPixmap.scaled(400, 200, Qt::KeepAspectRatio, Qt::SmoothTransformation)); nameLabel.setText(QString::fromStdString(user.name())); realNameLabel2.setText(QString::fromStdString(user.real_name())); @@ -129,32 +123,37 @@ void UserInfoBox::updateInfo(const ServerInfo_User &user) QString accountAgeString = tr("Unregistered user"); if (userLevel.testFlag(ServerInfo_User::IsAdmin) || userLevel.testFlag(ServerInfo_User::IsModerator) || userLevel.testFlag(ServerInfo_User::IsRegistered)) { - if (user.accountage_secs() == 0) - accountAgeString = tr("Unknown"); - else { - qint64 seconds = user.accountage_secs(); - qint64 minutes = seconds / SIXTY; - qint64 hours = minutes / SIXTY; - qint64 days = hours / HOURS_IN_A_DAY; - qint64 years = days / DAYS_IN_A_YEAR; - qint64 daysMinusYears = days - (years * DAYS_IN_A_YEAR); - - accountAgeString = ""; - if (years >= 1) { - accountAgeString = QString::number(years); - accountAgeString.append(" "); - accountAgeString.append(years == 1 ? tr("Year") : tr("Years")); - accountAgeString.append(" "); - } - - accountAgeString.append(QString::number(daysMinusYears)); - accountAgeString.append(" "); - accountAgeString.append(days == 1 ? tr("Day") : tr("Days")); - } + accountAgeString = getAgeString(user.accountage_secs()); } accountAgeLabel2.setText(accountAgeString); } +QString UserInfoBox::getAgeString(int ageSeconds) +{ + QString accountAgeString = tr("Unknown"); + if (ageSeconds == 0) + return accountAgeString; + + auto date = QDateTime::fromTime_t(QDateTime::currentSecsSinceEpoch() - ageSeconds).date(); + if (!date.isValid()) + return accountAgeString; + + QString dateString = QLocale().toString(date, QLocale::ShortFormat); + auto now = QDate::currentDate(); + auto daysAndYears = getDaysAndYearsBetween(date, now); + + QString yearString; + if (daysAndYears.second > 0) { + yearString = tr("%n Year(s), ", "amount of years (only shown if more than 0)", daysAndYears.second); + } + accountAgeString = + tr("%10%n Day(s) %20", "amount of years (if more than 0), amount of days, date in local short format", + daysAndYears.first) + .arg(yearString) + .arg(dateString); + return accountAgeString; +} + void UserInfoBox::updateInfo(const QString &userName) { Command_GetUserInfo cmd; @@ -171,6 +170,7 @@ void UserInfoBox::processResponse(const Response &r) { const Response_GetUserInfo &response = r.GetExtension(Response_GetUserInfo::ext); updateInfo(response.user_info()); + resize(sizeHint()); show(); } @@ -257,7 +257,7 @@ void UserInfoBox::processEditResponse(const Response &r) case Response::RespInternalError: default: QMessageBox::critical(this, tr("Error"), - tr("An error occured while trying to update your user informations.")); + tr("An error occurred while trying to update your user information.")); break; } } diff --git a/cockatrice/src/userinfobox.h b/cockatrice/src/userinfobox.h index 27ba1c81e..3f662c64a 100644 --- a/cockatrice/src/userinfobox.h +++ b/cockatrice/src/userinfobox.h @@ -1,6 +1,7 @@ #ifndef USERINFOBOX_H #define USERINFOBOX_H +#include #include #include #include @@ -20,9 +21,18 @@ private: QPushButton editButton, passwordButton, avatarButton; QPixmap avatarPixmap; + static QString getAgeString(int ageSeconds); + public: UserInfoBox(AbstractClient *_client, bool editable, QWidget *parent = nullptr, Qt::WindowFlags flags = {}); void retranslateUi(); + + inline static QPair getDaysAndYearsBetween(const QDate &then, const QDate &now) + { + int years = now.addDays(1 - then.dayOfYear()).year() - then.year(); // there is no yearsTo + int days = then.addYears(years).daysTo(now); + return {days, years}; + } private slots: void processResponse(const Response &r); void processEditResponse(const Response &r); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9a8ba8d06..9ca0bfeba 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,12 +1,15 @@ enable_testing() add_test(NAME dummy_test COMMAND dummy_test) add_test(NAME expression_test COMMAND expression_test) + +add_test(NAME test_age_formatting COMMAND test_age_formatting) add_test(NAME password_hash_test COMMAND password_hash_test) # Find GTest add_executable(dummy_test dummy_test.cpp) add_executable(expression_test expression_test.cpp) +add_executable(test_age_formatting test_age_formatting.cpp) add_executable(password_hash_test password_hash_test.cpp) find_package(GTest) @@ -37,6 +40,7 @@ if(NOT GTEST_FOUND) SET(GTEST_BOTH_LIBRARIES gtest) add_dependencies(dummy_test gtest) add_dependencies(expression_test gtest) + add_dependencies(test_age_formatting gtest) add_dependencies(password_hash_test gtest) endif() @@ -47,6 +51,7 @@ set(TEST_QT_MODULES Qt5::Widgets) include_directories(${GTEST_INCLUDE_DIRS}) target_link_libraries(dummy_test Threads::Threads ${GTEST_BOTH_LIBRARIES}) target_link_libraries(expression_test cockatrice_common Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES}) +target_link_libraries(test_age_formatting Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES}) target_link_libraries(password_hash_test cockatrice_common Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES}) add_subdirectory(carddatabase) diff --git a/tests/test_age_formatting.cpp b/tests/test_age_formatting.cpp new file mode 100644 index 000000000..88968f252 --- /dev/null +++ b/tests/test_age_formatting.cpp @@ -0,0 +1,44 @@ +#include "../cockatrice/src/userinfobox.h" + +#include "gtest/gtest.h" + +namespace +{ +using dayyear = QPair; + +TEST(AgeFormatting, Zero) +{ + auto got = UserInfoBox::getDaysAndYearsBetween(QDate(2000, 1, 1), QDate(2000, 1, 1)); + ASSERT_EQ(got, dayyear(0, 0)) << "these are the same day"; +} + +TEST(AgeFormatting, LeapDay) +{ + auto got = UserInfoBox::getDaysAndYearsBetween(QDate(2000, 2, 28), QDate(2000, 3, 1)); + ASSERT_EQ(got, dayyear(2, 0)) << "there is a leap day in between these days"; +} + +TEST(AgeFormatting, LeapYear) +{ + auto got = UserInfoBox::getDaysAndYearsBetween(QDate(2000, 1, 1), QDate(2001, 1, 1)); + ASSERT_EQ(got, dayyear(0, 1)) << "there is a leap day in between these dates, but that's fine"; +} + +TEST(AgeFormatting, LeapDayWithYear) +{ + auto got = UserInfoBox::getDaysAndYearsBetween(QDate(2000, 2, 28), QDate(2001, 3, 1)); + ASSERT_EQ(got, dayyear(1, 1)) << "there is a leap day in between these days but not in the last year"; +} + +TEST(AgeFormatting, LeapDayThisYear) +{ + auto got = UserInfoBox::getDaysAndYearsBetween(QDate(2003, 2, 28), QDate(2004, 3, 1)); + ASSERT_EQ(got, dayyear(2, 1)) << "there is a leap day in between these days this year"; +} +} // namespace + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}