From a226f0b58cac5e999b80fdc50bcc65a4d477309f Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 29 Aug 2025 14:14:00 +0300 Subject: [PATCH] Added toasts after review of unconfirmed authorizations. --- Telegram/Resources/langs/lang.strings | 7 ++ .../dialogs/dialogs_top_bar_suggestion.cpp | 99 ++++++++++++++++++- 2 files changed, 102 insertions(+), 4 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 415752d203..b00244a962 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4154,6 +4154,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_unconfirmed_auth_multiple#other" = "We detected new {count} logins to your account. Is it you?"; "lng_unconfirmed_auth_multiple_from#one" = "We detected new {count} login to your account from {country}. Is it you?"; "lng_unconfirmed_auth_multiple_from#other" = "We detected new {count} logins to your account from {country}. Is it you?"; +"lng_unconfirmed_auth_denied_title#one" = "New Login Prevented"; +"lng_unconfirmed_auth_denied_title#other" = "New Logins Prevented"; +"lng_unconfirmed_auth_denied_single" = "We have terminated the login attempt from {country}."; +"lng_unconfirmed_auth_denied_multiple" = "We have terminated the login attempts from: {country}"; +"lng_unconfirmed_auth_denied_warning" = "Never send your login code to anyone or you can lose your Telegram account!"; +"lng_unconfirmed_auth_confirmed" = "New Login Allowed"; +"lng_unconfirmed_auth_confirmed_message" = "You can check the list of your active logins in {link}."; "lng_about_random" = "Send a {emoji} emoji to any chat to try your luck."; "lng_about_random_send" = "Send"; diff --git a/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp b/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp index d40de08aa0..8d25e709f7 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp @@ -28,14 +28,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/profile/info_profile_values.h" #include "lang/lang_keys.h" #include "main/main_session.h" +#include "settings/settings_active_sessions.h" #include "settings/settings_credits_graphics.h" #include "settings/settings_premium.h" +#include "ui/boxes/confirm_box.h" #include "ui/controls/userpic_button.h" #include "ui/effects/credits_graphics.h" #include "ui/layers/generic_box.h" #include "ui/rect.h" #include "ui/text/format_values.h" #include "ui/text/text_utilities.h" +#include "ui/toast/toast.h" #include "ui/ui_utility.h" #include "ui/vertical_list.h" #include "ui/wrap/fade_wrap.h" @@ -58,6 +61,92 @@ namespace { return window->sessionController(); } +[[nodiscard]] QString FormatAuthInfo(const Data::UnreviewedAuth &auth) { + const auto location = auth.location.isEmpty() + ? QString() + : "\U0001F30D " + auth.location; + const auto device = auth.device.isEmpty() + ? QString() + : "\U0001F4F1 " + auth.device; + + if (!location.isEmpty() && !device.isEmpty()) { + return location + " (" + device + ")"; + } else if (!location.isEmpty()) { + return location; + } else if (!device.isEmpty()) { + return device; + } + return QString(); +} + +void ShowAuthToast( + not_null parent, + not_null session, + const std::vector &list, + bool confirmed) { + if (confirmed) { + auto text = tr::lng_unconfirmed_auth_confirmed_message( + tr::now, + lt_link, + Ui::Text::Link(tr::lng_settings_sessions_title(tr::now)), + Ui::Text::RichLangValue); + auto filter = [=]( + ClickHandlerPtr handler, + Qt::MouseButton button) { + if (const auto controller = FindSessionController(parent)) { + session->api().authorizations().reload(); + controller->showSettings(Settings::Sessions::Id()); + return false; + } + return true; + }; + Ui::Toast::Show(parent->window(), Ui::Toast::Config{ + .title = tr::lng_unconfirmed_auth_confirmed(tr::now), + .text = std::move(text), + .filter = std::move(filter), + .duration = crl::time(5000), + }); + } else { + auto messageText = QString(); + if (list.size() == 1) { + messageText = tr::lng_unconfirmed_auth_denied_single( + tr::now, + lt_country, + FormatAuthInfo(list.front())); + } else { + auto authList = QString('\n'); + for (auto i = 0; i < std::min(int(list.size()), 10); ++i) { + const auto info = FormatAuthInfo(list[i]); + if (!info.isEmpty()) { + authList += "• " + info + "\n"; + } + } + messageText = tr::lng_unconfirmed_auth_denied_multiple( + tr::now, + lt_country, + authList); + } + if (const auto controller = FindSessionController(parent)) { + const auto count = float64(list.size()); + controller->show(Box([=](not_null box) { + box->setTitle(tr::lng_unconfirmed_auth_denied_title( + lt_count, + rpl::single(count))); + Ui::InformBox(box, { + .text = TextWithEntities() + .append(messageText) + .append('\n') + .append( + tr::lng_unconfirmed_auth_denied_warning( + tr::now, + Ui::Text::Bold)), + .confirmText = tr::lng_archive_hint_button(tr::now), + }); + })); + } + } +} + constexpr auto kSugSetBirthday = "BIRTHDAY_SETUP"_cs; constexpr auto kSugBirthdayContacts = "BIRTHDAY_CONTACTS_TODAY"_cs; constexpr auto kSugPremiumAnnual = "PREMIUM_ANNUAL"_cs; @@ -147,14 +236,16 @@ rpl::producer*> TopBarSuggestionValue( const auto &list = session->api().authorizations().unreviewed(); const auto hashes = ranges::views::all( - list - ) | ranges::views::transform([](const auto &auth) { - return auth.hash; - }) | ranges::to_vector; + list + ) | ranges::views::transform([](const auto &auth) { + return auth.hash; + }) | ranges::to_vector; + const auto content = CreateUnconfirmedAuthContent( parent, list, [=](bool confirmed) { + ShowAuthToast(parent, session, list, confirmed); session->api().authorizations().review( hashes, confirmed);