diff --git a/CHANGELOG.md b/CHANGELOG.md index b1fdd0564af..d631f3ee9a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ - Minor: Added action to reset `/watching`. (#6759) - Minor: Removed messaging about running flatpak. This is already apparent in the newer Flatpak runtimes. (#6768) - Minor: Add `/(un)monitor` and `/(un)restrict` commands for moderators. (#6750, #6785) +- Minor: The follower mode duration in the split header now shows hours or days if possible. (#6812) - Bugfix: Fixed context menu hotkeys not working on macOS. (#6778) - Bugfix: Moderation checks now include the lead moderator badge. (#6642) - Bugfix: Fixed lead moderator badges not being filtered by the `Channel` badge setting. (#6665) diff --git a/src/util/FormatTime.cpp b/src/util/FormatTime.cpp index 0eefdda613c..0387a3edca2 100644 --- a/src/util/FormatTime.cpp +++ b/src/util/FormatTime.cpp @@ -5,6 +5,7 @@ #include "util/FormatTime.hpp" #include "common/QLogging.hpp" +#include "util/Helpers.hpp" #include #include @@ -183,6 +184,37 @@ QString formatTime(std::chrono::seconds totalSeconds, int components) components); } +QString formatDurationExact(std::chrono::seconds seconds) +{ + if (seconds.count() == 0) + { + return u"0s"_s; + } + + auto [value, unit] = [&]() -> std::pair { + int64_t value = seconds.count(); + if ((value % 60) != 0) + { + return {value, 's'}; + } + value /= 60; + if ((value % 60) != 0) + { + return {value, 'm'}; + } + value /= 60; + if ((value % 24) != 0) + { + return {value, 'h'}; + } + return {value / 24, 'd'}; + }(); + + auto str = localizeNumbers(value); + str += unit; + return str; +} + QString formatLongFriendlyDuration(const QDateTime &from, const QDateTime &to) { if (!from.isValid() || !to.isValid()) diff --git a/src/util/FormatTime.hpp b/src/util/FormatTime.hpp index f0a867c0dbe..30f084c466e 100644 --- a/src/util/FormatTime.hpp +++ b/src/util/FormatTime.hpp @@ -17,6 +17,16 @@ QString formatTime(int totalSeconds, int components = 4); QString formatTime(const QString &totalSecondsString, int components = 4); QString formatTime(std::chrono::seconds totalSeconds, int components = 4); +/// Format a duration with one component while showing the exact value. +/// +/// **Examples**: +/// - `2` formats as `2s` +/// - `120` formats as `2m` +/// - `121` formats as `121s` +/// +/// Supports seconds, minutes, hours, and days. +QString formatDurationExact(std::chrono::seconds seconds); + /// Formats a duration that's expected to be long (sevreal months or years) like /// "4 years, 5 days and 8 hours". /// diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index 9078567d518..a677b4407f9 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -21,6 +21,7 @@ #include "singletons/StreamerMode.hpp" #include "singletons/Theme.hpp" #include "singletons/WindowManager.hpp" +#include "util/FormatTime.hpp" #include "util/Helpers.hpp" #include "util/LayoutHelper.hpp" #include "widgets/buttons/DrawnButton.hpp" @@ -82,8 +83,9 @@ auto formatRoomModeUnclean( { if (modes->followerOnly != 0) { - text += QString("follow(%1m), ") - .arg(localizeNumbers(modes->followerOnly)); + text += QString("follow(%1), ") + .arg(formatDurationExact( + std::chrono::minutes{modes->followerOnly})); } else { diff --git a/tests/src/FormatTime.cpp b/tests/src/FormatTime.cpp index 76933bdeb4f..ff9c9265970 100644 --- a/tests/src/FormatTime.cpp +++ b/tests/src/FormatTime.cpp @@ -210,6 +210,47 @@ TEST(FormatTime, chrono) } } +TEST(FormatTime, formatDurationExact) +{ + struct Case { + std::chrono::seconds input; + QStringView output; + }; + std::vector cases{ + {.input = 0s, .output = u"0s"}, + {.input = 1s, .output = u"1s"}, + {.input = 10s, .output = u"10s"}, + {.input = 59s, .output = u"59s"}, + {.input = 60s, .output = u"1m"}, + {.input = 61s, .output = u"61s"}, + {.input = 64s, .output = u"64s"}, + {.input = 2min, .output = u"2m"}, + {.input = 10min, .output = u"10m"}, + {.input = 10min + 2s, .output = u"602s"}, + {.input = 59min, .output = u"59m"}, + {.input = 1h, .output = u"1h"}, + {.input = 1h + 1min, .output = u"61m"}, + {.input = 1h + 1min + 1s, .output = u"3,661s"}, + {.input = 10h, .output = u"10h"}, + {.input = 10h + 2s, .output = u"36,002s"}, + {.input = 23h, .output = u"23h"}, + {.input = 24h, .output = u"1d"}, + {.input = 25h, .output = u"25h"}, + {.input = 5 * 24h, .output = u"5d"}, + {.input = 7 * 24h, .output = u"7d"}, + {.input = 14 * 24h, .output = u"14d"}, + {.input = 28 * 24h, .output = u"28d"}, + {.input = 30 * 24h, .output = u"30d"}, + {.input = 31 * 24h, .output = u"31d"}, + }; + + for (const auto &c : cases) + { + ASSERT_EQ(formatDurationExact(c.input), c.output) + << "Input: " << c.input.count() << 's'; + } +} + TEST(FormatTime, formatLongFriendlyDuration) { struct Case { diff --git a/tests/src/main.cpp b/tests/src/main.cpp index 22b19a604a3..2e865f90ee3 100644 --- a/tests/src/main.cpp +++ b/tests/src/main.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,8 @@ int main(int argc, char **argv) QApplication app(argc, argv); // make sure to always debug-log QLoggingCategory::setFilterRules("chatterino.*=true"); + // make sure we use the same language when formatting + QLocale::setDefault(QLocale("en_GB")); initResources();