From 2bb1c5d39bee72218d65e2db025c5934b2b0e0e0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 7 Jan 2025 11:15:57 +0400 Subject: [PATCH 01/17] Show verify badge on Verifications Codes. --- .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 68 ++++++++++--------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index f37b6c537230fe..7e6277f953aec3 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -411,11 +411,11 @@ void PaintRow( from, videoUserpic, context, - context.narrow + (context.narrow && !badgesState.empty() && !draft && item - && !item->isEmpty()); + && !item->isEmpty())); } const auto nameleft = context.st->nameLeft; @@ -705,12 +705,46 @@ void PaintRow( } p.setFont(st::semiboldFont); + const auto paintPeerBadge = [&] { + const auto badgeWidth = rowBadge.drawGetWidth(p, { + .peer = from, + .rectForName = rectForName, + .nameWidth = rowName.maxWidth(), + .outerWidth = context.width, + .verified = (context.active + ? &st::dialogsVerifiedIconActive + : context.selected + ? &st::dialogsVerifiedIconOver + : &st::dialogsVerifiedIcon), + .premium = &ThreeStateIcon( + st::dialogsPremiumIcon, + context.active, + context.selected), + .scam = (context.active + ? &st::dialogsScamFgActive + : context.selected + ? &st::dialogsScamFgOver + : &st::dialogsScamFg), + .premiumFg = (context.active + ? &st::dialogsVerifiedIconBgActive + : context.selected + ? &st::dialogsVerifiedIconBgOver + : &st::dialogsVerifiedIconBg), + .customEmojiRepaint = customEmojiRepaint, + .now = context.now, + .paused = context.paused, + }); + rectForName.setWidth(rectForName.width() - badgeWidth); + }; if (flags & (Flag::SavedMessages | Flag::RepliesMessages | Flag::VerifyCodes | Flag::HiddenAuthor | Flag::MyNotes)) { + if (!context.search && (flags & Flag::VerifyCodes)) { + paintPeerBadge(); + } auto text = (flags & Flag::SavedMessages) ? tr::lng_saved_messages(tr::now) : (flags & Flag::RepliesMessages) @@ -736,35 +770,7 @@ void PaintRow( text); } else if (from) { if ((history || sublist) && !context.search) { - const auto badgeWidth = rowBadge.drawGetWidth(p, { - .peer = from, - .rectForName = rectForName, - .nameWidth = rowName.maxWidth(), - .outerWidth = context.width, - .verified = (context.active - ? &st::dialogsVerifiedIconActive - : context.selected - ? &st::dialogsVerifiedIconOver - : &st::dialogsVerifiedIcon), - .premium = &ThreeStateIcon( - st::dialogsPremiumIcon, - context.active, - context.selected), - .scam = (context.active - ? &st::dialogsScamFgActive - : context.selected - ? &st::dialogsScamFgOver - : &st::dialogsScamFg), - .premiumFg = (context.active - ? &st::dialogsVerifiedIconBgActive - : context.selected - ? &st::dialogsVerifiedIconBgOver - : &st::dialogsVerifiedIconBg), - .customEmojiRepaint = customEmojiRepaint, - .now = context.now, - .paused = context.paused, - }); - rectForName.setWidth(rectForName.width() - badgeWidth); + paintPeerBadge(); } p.setPen(context.active ? st::dialogsNameFgActive From 9d68ef64210b3044428b552777a86180f66dfde3 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 7 Jan 2025 20:53:43 +0400 Subject: [PATCH 02/17] Fix bot verification showing second check. --- Telegram/SourceFiles/info/profile/info_profile_badge.cpp | 1 + Telegram/SourceFiles/info/profile/info_profile_badge.h | 7 ++++--- Telegram/SourceFiles/info/profile/info_profile_cover.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/info/profile/info_profile_badge.cpp b/Telegram/SourceFiles/info/profile/info_profile_badge.cpp index 8b0bb185fd6aa2..4f63aedfa77223 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_badge.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_badge.cpp @@ -117,6 +117,7 @@ void Badge::setContent(Content content) { _view->show(); switch (_content.badge) { case BadgeType::Verified: + case BadgeType::BotVerified: case BadgeType::Premium: { const auto id = _content.emojiStatusId; const auto emoji = id diff --git a/Telegram/SourceFiles/info/profile/info_profile_badge.h b/Telegram/SourceFiles/info/profile/info_profile_badge.h index f0e770d3f468d2..6b7512fc3d068b 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_badge.h +++ b/Telegram/SourceFiles/info/profile/info_profile_badge.h @@ -38,9 +38,10 @@ class EmojiStatusPanel; enum class BadgeType { None = 0x00, Verified = 0x01, - Premium = 0x02, - Scam = 0x04, - Fake = 0x08, + BotVerified = 0x02, + Premium = 0x04, + Scam = 0x08, + Fake = 0x10, }; inline constexpr bool is_flag_type(BadgeType) { return true; } diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index 79a72614acc114..f76e8b6c95a8c5 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -311,7 +311,7 @@ Cover::Cover( ) | rpl::map([=] { const auto info = peer->botVerifyDetails(); return Badge::Content{ - .badge = info ? BadgeType::Verified : BadgeType::None, + .badge = info ? BadgeType::BotVerified : BadgeType::None, .emojiStatusId = info ? info->iconId : DocumentId(), }; }); From 86319be2567cdce73282661ad0dc4872adc8adcd Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 7 Jan 2025 21:23:42 +0400 Subject: [PATCH 03/17] Version 5.10.2. - Fix double verification badge in profiles. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 ++++---- Telegram/Resources/winrc/Updater.rc | 8 ++++---- Telegram/SourceFiles/core/version.h | 4 ++-- Telegram/build/version | 8 ++++---- changelog.txt | 4 ++++ 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 84822a3b30c613..abf0a27b09e194 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ + Version="5.10.2.0" /> Telegram Desktop Telegram Messenger LLP diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index c57c1d00f5bd19..1fde9162b86453 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 5,10,1,0 - PRODUCTVERSION 5,10,1,0 + FILEVERSION 5,10,2,0 + PRODUCTVERSION 5,10,2,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "5.10.1.0" + VALUE "FileVersion", "5.10.2.0" VALUE "LegalCopyright", "Copyright (C) 2014-2025" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "5.10.1.0" + VALUE "ProductVersion", "5.10.2.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 4e3e821d0c106f..2e8b8b2cc09e56 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 5,10,1,0 - PRODUCTVERSION 5,10,1,0 + FILEVERSION 5,10,2,0 + PRODUCTVERSION 5,10,2,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -53,10 +53,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "5.10.1.0" + VALUE "FileVersion", "5.10.2.0" VALUE "LegalCopyright", "Copyright (C) 2014-2025" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "5.10.1.0" + VALUE "ProductVersion", "5.10.2.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index a88138c551a0f3..410f5fa2948769 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs; constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs; constexpr auto AppName = "Telegram Desktop"_cs; constexpr auto AppFile = "Telegram"_cs; -constexpr auto AppVersion = 5010001; -constexpr auto AppVersionStr = "5.10.1"; +constexpr auto AppVersion = 5010002; +constexpr auto AppVersionStr = "5.10.2"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 6425649d225507..7c5b4081ae7778 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 5010001 +AppVersion 5010002 AppVersionStrMajor 5.10 -AppVersionStrSmall 5.10.1 -AppVersionStr 5.10.1 +AppVersionStrSmall 5.10.2 +AppVersionStr 5.10.2 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 5.10.1 +AppVersionOriginal 5.10.2 diff --git a/changelog.txt b/changelog.txt index 93bf84df3e8037..4f0992130acbf0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +5.10.2 (07.01.25) + +- Fix double verification badge in profiles. + 5.10.1 (06.01.25) - Show "Boost group the send messages" information. From 88a310a86e656933269e62fc46721d989cf9514c Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 7 Jan 2025 21:31:06 +0400 Subject: [PATCH 04/17] Version 5.10.2: Hide unique gift userpic. --- Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp index 168b2ea9a24923..746984b278edea 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp @@ -39,7 +39,7 @@ constexpr auto kPerPage = 50; .from = ((gift.anonymous || !gift.fromId) ? nullptr : to->owner().peer(gift.fromId).get()), - .userpic = true, + .userpic = !gift.info.unique, .hidden = gift.hidden, .mine = to->isSelf(), }; From 2ab725e5e1ad886f9788c14a7f1eb83cbdf05f4a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 6 Jan 2025 21:00:49 +0300 Subject: [PATCH 05/17] Added patch for colors of strikeout format to Linux. --- Telegram/build/prepare/prepare.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/build/prepare/prepare.py b/Telegram/build/prepare/prepare.py index 31dacb2c2b7275..e83b31a4b3307a 100644 --- a/Telegram/build/prepare/prepare.py +++ b/Telegram/build/prepare/prepare.py @@ -457,7 +457,7 @@ def runStages(): stage('patches', """ git clone https://github.com/desktop-app/patches.git cd patches - git checkout b3d7243fe1 + git checkout 748e206a97 """) stage('msys64', """ From 1b6a7fafa8520cc8dc495a6596b50a480ddd9e3a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 7 Jan 2025 09:29:06 +0300 Subject: [PATCH 06/17] Added ability to instantly delete account in test DC. --- .../boxes/self_destruction_box.cpp | 81 +++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/boxes/self_destruction_box.cpp b/Telegram/SourceFiles/boxes/self_destruction_box.cpp index 21073506345e4c..c4a070c16e6d42 100644 --- a/Telegram/SourceFiles/boxes/self_destruction_box.cpp +++ b/Telegram/SourceFiles/boxes/self_destruction_box.cpp @@ -7,20 +7,89 @@ For license and copyright information please follow this link: */ #include "boxes/self_destruction_box.h" +#include "api/api_authorizations.h" +#include "api/api_cloud_password.h" +#include "api/api_self_destruct.h" +#include "apiwrap.h" +#include "boxes/passcode_box.h" #include "lang/lang_keys.h" +#include "main/main_session.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/labels.h" -#include "apiwrap.h" -#include "api/api_self_destruct.h" -#include "api/api_authorizations.h" -#include "main/main_session.h" -#include "styles/style_layers.h" +#include "ui/text/text_utilities.h" +#include "ui/widgets/menu/menu_add_action_callback.h" +#include "ui/widgets/menu/menu_add_action_callback_factory.h" +#include "ui/widgets/popup_menu.h" #include "styles/style_boxes.h" +#include "styles/style_info.h" +#include "styles/style_layers.h" +#include "styles/style_menu_icons.h" +#include "styles/style_widgets.h" namespace { using Type = SelfDestructionBox::Type; +void AddDeleteAccount( + not_null box, + not_null session) { + if (!session->isTestMode()) { + return; + } + const auto maybeState = session->api().cloudPassword().stateCurrent(); + if (!maybeState || !maybeState->hasPassword) { + return; + } + const auto top = box->addTopButton(st::infoTopBarMenu); + const auto menu + = top->lifetime().make_state>(); + const auto handler = [=] { + session->api().cloudPassword().state( + ) | rpl::take( + 1 + ) | rpl::start_with_next([=](const Core::CloudPasswordState &state) { + auto fields = PasscodeBox::CloudFields::From(state); + fields.customTitle = tr::lng_settings_destroy_title(); + fields.customDescription = tr::lng_context_mark_read_all_sure_2( + tr::now, + Ui::Text::RichLangValue).text; + fields.customSubmitButton = tr::lng_theme_delete(); + fields.customCheckCallback = [=]( + const Core::CloudPasswordResult &result, + QPointer box) { + session->api().request(MTPaccount_DeleteAccount( + MTP_flags(MTPaccount_DeleteAccount::Flag::f_password), + MTP_string("Manual"), + result.result + )).done([=] { + if (box) { + box->uiShow()->hideLayer(); + } + }).fail([=](const MTP::Error &error) { + if (box) { + box->handleCustomCheckError(error.type()); + } + }).send(); + }; + box->uiShow()->showBox(Box(session, fields)); + }, top->lifetime()); + }; + top->setClickedCallback([=] { + *menu = base::make_unique_q( + top, + st::popupMenuWithIcons); + + const auto addAction = Ui::Menu::CreateAddActionCallback(menu->get()); + addAction({ + .text = tr::lng_settings_destroy_title(tr::now), + .handler = handler, + .icon = &st::menuIconDeleteAttention, + .isAttention = true, + }); + (*menu)->popup(QCursor::pos()); + }); +} + [[nodiscard]] std::vector Values(Type type) { switch (type) { case Type::Account: return { 30, 90, 180, 365, 548, 720 }; @@ -151,4 +220,6 @@ void SelfDestructionBox::prepare() { } else { showContent(); } + + AddDeleteAccount(this, _session); } From 5df2a048e182e361f6cb8f0b27a925cae3d4463e Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 7 Jan 2025 23:09:35 +0300 Subject: [PATCH 07/17] Fixed ability to copy selected text with presented compose search. --- Telegram/SourceFiles/history/history_widget.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 2b890fd261ba81..c810d87d4e696b 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1930,7 +1930,7 @@ void HistoryWidget::activate() { void HistoryWidget::setInnerFocus() { if (_list) { - if (isSearching()) { + if (isSearching() && !_nonEmptySelection) { _composeSearch->setInnerFocus(); } else if (isChoosingTheme()) { _chooseTheme->setFocus(); @@ -8422,7 +8422,11 @@ void HistoryWidget::confirmDeleteSelected() { void HistoryWidget::escape() { if (_composeSearch) { - _composeSearch->hideAnimated(); + if (_nonEmptySelection) { + clearSelected(); + } else { + _composeSearch->hideAnimated(); + } } else if (_chooseForReport) { controller()->clearChooseReportMessages(); } else if (_nonEmptySelection && _list) { @@ -8522,7 +8526,7 @@ void HistoryWidget::updateTopBarSelection() { updateHistoryGeometry(); if (!controller()->isLayerShown() && !Core::App().passcodeLocked()) { - if (isSearching()) { + if (isSearching() && !_nonEmptySelection) { _composeSearch->setInnerFocus(); } else if (_nonEmptySelection || (_list && _list->wasSelectedText()) From ce4a081155cad742affe6f7fdde3f51e6dcf19a4 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 7 Jan 2025 23:37:08 +0300 Subject: [PATCH 08/17] Added initial ability to handle middle button in peer lists. --- Telegram/SourceFiles/boxes/peer_list_box.cpp | 4 ++++ Telegram/SourceFiles/boxes/peer_list_box.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index 22e08693388405..69d304a1481f8b 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -1680,6 +1680,10 @@ void PeerListContent::mousePressReleased(Qt::MouseButton button) { _controller->rowClicked(row); } } + } else if (button == Qt::MiddleButton && pressed == _selected) { + if (auto row = getRow(pressed.index)) { + _controller->rowMiddleClicked(row); + } } } diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h index f60c98135df6c4..c4a79c456b106b 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.h +++ b/Telegram/SourceFiles/boxes/peer_list_box.h @@ -482,6 +482,8 @@ class PeerListController : public PeerListSearchDelegate { } virtual void rowClicked(not_null row) = 0; + virtual void rowMiddleClicked(not_null row) { + } virtual void rowRightActionClicked(not_null row) { } From b7162b5fad7a5a752f22616e981b376e382f1233 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 7 Jan 2025 23:37:50 +0300 Subject: [PATCH 09/17] Added ability to open recent peers in window with middle button. --- Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp index 03b9a385c4491b..d13f336f938260 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp @@ -416,6 +416,7 @@ class Suggestions::ObjectListController } void rowClicked(not_null row) override; + void rowMiddleClicked(not_null row) override; bool rowTrackPress(not_null row) override; void rowTrackPressCancel() override; bool rowTrackPressSkipMouseSelection() override; @@ -673,6 +674,11 @@ void Suggestions::ObjectListController::rowClicked( _chosen.fire(row->peer()); } +void Suggestions::ObjectListController::rowMiddleClicked( + not_null row) { + window()->showInNewWindow(row->peer()); +} + void Suggestions::ObjectListController::setupPlainDivider( rpl::producer title) { auto result = object_ptr( From aab7ba264c172820880c9626e93b09f1929b9744 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 7 Jan 2025 23:45:07 +0300 Subject: [PATCH 10/17] Added ability to open peers in window with middle button from contacts. --- .../SourceFiles/boxes/peer_list_controllers.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 05b8d6d209b1e8..ff3e2722a235a8 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -43,6 +43,7 @@ For license and copyright information please follow this link: #include "dialogs/dialogs_main_list.h" #include "ui/effects/outline_segments.h" #include "ui/wrap/slide_wrap.h" +#include "window/window_separate_id.h" #include "window/window_session_controller.h" // showAddContact() #include "base/unixtime.h" #include "styles/style_boxes.h" @@ -64,6 +65,10 @@ object_ptr PrepareContactsBox( public: using ContactsBoxController::ContactsBoxController; + [[nodiscard]] rpl::producer> wheelClicks() const { + return _wheelClicks.events(); + } + protected: std::unique_ptr createRow( not_null user) override { @@ -72,6 +77,14 @@ object_ptr PrepareContactsBox( : nullptr; } + void rowMiddleClicked( + not_null row) override { + _wheelClicks.fire(row->peer()); + } + + private: + rpl::event_stream> _wheelClicks; + }; auto controller = std::make_unique( &sessionController->session()); @@ -100,6 +113,10 @@ object_ptr PrepareContactsBox( online ? &st::contactsSortOnlineIconOver : nullptr); }); raw->setSortMode(Mode::Online); + + raw->wheelClicks() | rpl::start_with_next([=](not_null p) { + sessionController->showInNewWindow(p); + }, box->lifetime()); }; return Box(std::move(controller), std::move(init)); } From 43dfe559a6471a5dd3ce4ad48250c77401500c48 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 8 Jan 2025 09:45:33 +0300 Subject: [PATCH 11/17] Added simple context for marked text. --- Telegram/SourceFiles/core/ui_integration.cpp | 6 +++++- Telegram/lib_ui | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/core/ui_integration.cpp b/Telegram/SourceFiles/core/ui_integration.cpp index b7a88ed573ab22..40604a6c4d4e32 100644 --- a/Telegram/SourceFiles/core/ui_integration.cpp +++ b/Telegram/SourceFiles/core/ui_integration.cpp @@ -295,7 +295,11 @@ std::unique_ptr UiIntegration::createCustomEmoji( Fn UiIntegration::createSpoilerRepaint(const std::any &context) { const auto my = std::any_cast(&context); - return my ? my->customEmojiRepaint : nullptr; + if (my) { + return my->customEmojiRepaint; + } + const auto common = std::any_cast(&context); + return common ? common->repaint : nullptr; } rpl::producer<> UiIntegration::forcePopupMenuHideRequests() { diff --git a/Telegram/lib_ui b/Telegram/lib_ui index da44ac82a99ec0..d54a4bb510a730 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit da44ac82a99ec05d7091eaaf6ae96a63bbae3714 +Subproject commit d54a4bb510a730d519f6085f81ca021c610402ee From 9e18964e7f9c24b8ba1e2f1afac28698b2e41594 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 8 Jan 2025 10:15:28 +0300 Subject: [PATCH 12/17] Added spoiler entity to email pattern in intro and cloud password. --- .../SourceFiles/intro/intro_password_check.cpp | 8 ++++++-- Telegram/SourceFiles/intro/intro_step.cpp | 14 +++++++++++++- .../settings_cloud_password_common.cpp | 12 ++++++++++-- .../settings_cloud_password_common.h | 2 +- .../settings_cloud_password_email_confirm.cpp | 16 +++++++++------- .../settings_cloud_password_input.cpp | 4 +++- Telegram/lib_ui | 2 +- 7 files changed, 43 insertions(+), 15 deletions(-) diff --git a/Telegram/SourceFiles/intro/intro_password_check.cpp b/Telegram/SourceFiles/intro/intro_password_check.cpp index cd73d9867facc3..3555c95ef8d302 100644 --- a/Telegram/SourceFiles/intro/intro_password_check.cpp +++ b/Telegram/SourceFiles/intro/intro_password_check.cpp @@ -14,6 +14,7 @@ For license and copyright information please follow this link: #include "boxes/passcode_box.h" #include "lang/lang_keys.h" #include "intro/intro_signup.h" +#include "ui/text/text_utilities.h" #include "ui/widgets/buttons.h" #include "ui/widgets/fields/input_field.h" #include "ui/widgets/fields/password_input.h" @@ -350,8 +351,11 @@ void PasswordCheckWidget::updateDescriptionText() { auto pwdHidden = _pwdField->isHidden(); auto emailPattern = _emailPattern; setDescriptionText(pwdHidden - ? tr::lng_signin_recover_desc(lt_email, rpl::single(emailPattern)) - : tr::lng_signin_desc()); + ? tr::lng_signin_recover_desc( + lt_email, + rpl::single(Ui::Text::WrapEmailPattern(emailPattern)), + Ui::Text::WithEntities) + : tr::lng_signin_desc(Ui::Text::WithEntities)); } void PasswordCheckWidget::submit() { diff --git a/Telegram/SourceFiles/intro/intro_step.cpp b/Telegram/SourceFiles/intro/intro_step.cpp index e019da12489559..78f7b6f48b4df0 100644 --- a/Telegram/SourceFiles/intro/intro_step.cpp +++ b/Telegram/SourceFiles/intro/intro_step.cpp @@ -99,7 +99,19 @@ Step::Step( _descriptionText.value( ) | rpl::start_with_next([=](const TextWithEntities &text) { - _description->entity()->setMarkedText(text); + const auto label = _description->entity(); + const auto hasSpoiler = ranges::contains( + text.entities, + EntityType::Spoiler, + &EntityInText::type); + if (hasSpoiler) { + label->setMarkedText( + text, + CommonTextContext{ [=] { label->update(); } }); + } else { + label->setMarkedText(text); + } + label->setAttribute(Qt::WA_TransparentForMouseEvents, hasSpoiler); updateLabelsPosition(); }, lifetime()); } diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp index 0b627337921473..3c1f5e376021d7 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp @@ -118,7 +118,7 @@ void SetupHeader( const QString &lottie, rpl::producer<> &&showFinished, rpl::producer &&subtitle, - rpl::producer &&about) { + v::text::data &&about) { if (!lottie.isEmpty()) { const auto &size = st::settingsCloudPasswordIconSize; auto icon = CreateLottieIcon( @@ -148,8 +148,16 @@ void SetupHeader( const auto wrap = content->add( object_ptr>( content, - object_ptr(content, std::move(about), st)), + object_ptr( + content, + v::text::take_marked(std::move(about)), + st, + st::defaultPopupMenu, + [=](Fn update) { + return CommonTextContext{ std::move(update) }; + })), st::changePhoneDescriptionPadding); + wrap->setAttribute(Qt::WA_TransparentForMouseEvents); wrap->resize( wrap->width(), st::settingLocalPasscodeDescriptionHeight); diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.h b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.h index 95d8cca5d4f964..836728b4821a85 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.h +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.h @@ -50,7 +50,7 @@ void SetupHeader( const QString &lottie, rpl::producer<> &&showFinished, rpl::producer &&subtitle, - rpl::producer &&about); + v::text::data &&about); [[nodiscard]] not_null AddPasswordField( not_null content, diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email_confirm.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email_confirm.cpp index b1879387e87c59..7bf21c9d53b940 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email_confirm.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email_confirm.cpp @@ -22,6 +22,7 @@ For license and copyright information please follow this link: #include "ui/vertical_list.h" #include "ui/boxes/confirm_box.h" #include "ui/text/format_values.h" +#include "ui/text/text_utilities.h" #include "ui/widgets/menu/menu_add_action_callback.h" #include "ui/widgets/buttons.h" #include "ui/widgets/sent_code_field.h" @@ -138,13 +139,14 @@ void EmailConfirm::setupContent() { state->unconfirmedPattern.isEmpty() ? tr::lng_settings_cloud_password_email_recovery_subtitle() : tr::lng_cloud_password_confirm(), - rpl::single( - tr::lng_cloud_password_waiting_code( - tr::now, - lt_email, - state->unconfirmedPattern.isEmpty() - ? recoverEmailPattern - : state->unconfirmedPattern))); + tr::lng_cloud_password_waiting_code( + lt_email, + rpl::single( + Ui::Text::WrapEmailPattern( + state->unconfirmedPattern.isEmpty() + ? recoverEmailPattern + : state->unconfirmedPattern)), + TextWithEntities::Simple)); Ui::AddSkip(content, st::settingLocalPasscodeDescriptionBottomSkip); diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp index fc16b817998ace..b25659f3f8c086 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp @@ -183,7 +183,9 @@ void Input::setupContent() { : hasPassword ? tr::lng_settings_cloud_password_manage_password_change() : tr::lng_settings_cloud_password_password_subtitle(), - tr::lng_cloud_password_about()); + isCheck + ? tr::lng_settings_cloud_password_manage_about1() + : tr::lng_cloud_password_about()); Ui::AddSkip(content, st::settingLocalPasscodeDescriptionBottomSkip); diff --git a/Telegram/lib_ui b/Telegram/lib_ui index d54a4bb510a730..517be45510ffde 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit d54a4bb510a730d519f6085f81ca021c610402ee +Subproject commit 517be45510ffde54ccb928788d700f93cfba3b65 From 2b13fc9a24070c0fa0109427bd330ab7053bb7bc Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 8 Jan 2025 10:35:45 +0300 Subject: [PATCH 13/17] Slightly simplified Intro::Step::setDescriptionText. --- Telegram/SourceFiles/intro/intro_step.cpp | 11 ++--------- Telegram/SourceFiles/intro/intro_step.h | 5 ++--- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Telegram/SourceFiles/intro/intro_step.cpp b/Telegram/SourceFiles/intro/intro_step.cpp index 78f7b6f48b4df0..c8d9a3d595c2b7 100644 --- a/Telegram/SourceFiles/intro/intro_step.cpp +++ b/Telegram/SourceFiles/intro/intro_step.cpp @@ -294,15 +294,8 @@ void Step::setTitleText(rpl::producer titleText) { _titleText = std::move(titleText); } -void Step::setDescriptionText( - rpl::producer descriptionText) { - setDescriptionText( - std::move(descriptionText) | Ui::Text::ToWithEntities()); -} - -void Step::setDescriptionText( - rpl::producer richDescriptionText) { - _descriptionText = std::move(richDescriptionText); +void Step::setDescriptionText(v::text::data &&descriptionText) { + _descriptionText = v::text::take_marked(std::move(descriptionText)); } void Step::showFinished() { diff --git a/Telegram/SourceFiles/intro/intro_step.h b/Telegram/SourceFiles/intro/intro_step.h index f265a4a984a03b..32ba62926ccfe3 100644 --- a/Telegram/SourceFiles/intro/intro_step.h +++ b/Telegram/SourceFiles/intro/intro_step.h @@ -9,6 +9,7 @@ For license and copyright information please follow this link: #include "base/object_ptr.h" #include "mtproto/sender.h" +#include "ui/text/text_variant.h" #include "ui/rp_widget.h" #include "ui/effects/animations.h" @@ -98,9 +99,7 @@ class Step : public Ui::RpWidget { void resizeEvent(QResizeEvent *e) override; void setTitleText(rpl::producer titleText); - void setDescriptionText(rpl::producer descriptionText); - void setDescriptionText( - rpl::producer richDescriptionText); + void setDescriptionText(v::text::data &&descriptionText); bool paintAnimated(QPainter &p, QRect clip); void fillSentCodeData(const MTPDauth_sentCode &type); From 2b71625ffe77ed75d63b212fb2fb1f7e5e090e5a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 8 Jan 2025 10:56:46 +0300 Subject: [PATCH 14/17] Moved out part of common code for cloud password to td_ui. --- Telegram/CMakeLists.txt | 4 +- .../settings_cloud_password_common.cpp | 124 +---------------- .../settings_cloud_password_common.h | 75 +---------- .../settings_cloud_password_email.cpp | 1 + .../settings_cloud_password_email_confirm.cpp | 1 + .../settings_cloud_password_hint.cpp | 1 + .../settings_cloud_password_input.cpp | 1 + .../settings_cloud_password_manage.cpp | 7 +- .../settings_cloud_password_start.cpp | 1 + .../settings_cloud_password_step.cpp | 126 ++++++++++++++++++ .../settings_cloud_password_step.h | 89 +++++++++++++ .../settings/settings_local_passcode.cpp | 7 +- Telegram/cmake/td_ui.cmake | 2 + 13 files changed, 247 insertions(+), 192 deletions(-) create mode 100644 Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_step.cpp create mode 100644 Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_step.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 1e0365f37f2f26..1071fbe7acb947 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1409,8 +1409,6 @@ PRIVATE settings/business/settings_recipients_helper.h settings/business/settings_working_hours.cpp settings/business/settings_working_hours.h - settings/cloud_password/settings_cloud_password_common.cpp - settings/cloud_password/settings_cloud_password_common.h settings/cloud_password/settings_cloud_password_email.cpp settings/cloud_password/settings_cloud_password_email.h settings/cloud_password/settings_cloud_password_email_confirm.cpp @@ -1423,6 +1421,8 @@ PRIVATE settings/cloud_password/settings_cloud_password_manage.h settings/cloud_password/settings_cloud_password_start.cpp settings/cloud_password/settings_cloud_password_start.h + settings/cloud_password/settings_cloud_password_step.cpp + settings/cloud_password/settings_cloud_password_step.h settings/settings_active_sessions.cpp settings/settings_active_sessions.h settings/settings_advanced.cpp diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp index 3c1f5e376021d7..4b6c8024fafcac 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.cpp @@ -7,28 +7,16 @@ For license and copyright information please follow this link: */ #include "settings/cloud_password/settings_cloud_password_common.h" -#include "apiwrap.h" -#include "base/timer.h" -#include "core/application.h" #include "lang/lang_keys.h" #include "lottie/lottie_icon.h" -#include "main/main_session.h" -#include "settings/cloud_password/settings_cloud_password_email.h" -#include "settings/cloud_password/settings_cloud_password_email_confirm.h" -#include "settings/cloud_password/settings_cloud_password_hint.h" -#include "settings/cloud_password/settings_cloud_password_input.h" -#include "settings/cloud_password/settings_cloud_password_manage.h" -#include "settings/cloud_password/settings_cloud_password_start.h" -#include "ui/boxes/confirm_box.h" +#include "settings/settings_common.h" +#include "ui/vertical_list.h" #include "ui/widgets/buttons.h" #include "ui/widgets/fields/input_field.h" #include "ui/widgets/fields/password_input.h" #include "ui/widgets/labels.h" #include "ui/wrap/vertical_layout.h" -#include "ui/vertical_list.h" -#include "window/window_session_controller.h" #include "styles/style_boxes.h" -#include "styles/style_layers.h" #include "styles/style_settings.h" namespace Settings::CloudPassword { @@ -100,12 +88,15 @@ BottomButton CreateBottomDisableButton( }; } -void SetupAutoCloseTimer(rpl::lifetime &lifetime, Fn callback) { +void SetupAutoCloseTimer( + rpl::lifetime &lifetime, + Fn callback, + Fn lastNonIdleTime) { constexpr auto kTimerCheck = crl::time(1000 * 60); constexpr auto kAutoCloseTimeout = crl::time(1000 * 60 * 10); const auto timer = lifetime.make_state([=] { - const auto idle = crl::now() - Core::App().lastNonIdleTime(); + const auto idle = crl::now() - lastNonIdleTime(); if (idle >= kAutoCloseTimeout) { callback(); } @@ -269,105 +260,4 @@ void AddSkipInsteadOfError(not_null content) { dummy = nullptr; } -AbstractStep::AbstractStep( - QWidget *parent, - not_null controller) -: AbstractSection(parent) -, _controller(controller) { -} - -not_null AbstractStep::controller() const { - return _controller; -} - -Api::CloudPassword &AbstractStep::cloudPassword() { - return _controller->session().api().cloudPassword(); -} - -rpl::producer AbstractStep::removeTypes() { - return rpl::never(); -} - -void AbstractStep::showBack() { - _showBack.fire({}); -} - -void AbstractStep::showOther(Type type) { - _showOther.fire_copy(type); -} - -void AbstractStep::setFocusCallback(Fn callback) { - _setInnerFocusCallback = callback; -} - -rpl::producer<> AbstractStep::showFinishes() const { - return _showFinished.events(); -} - -void AbstractStep::showFinished() { - _showFinished.fire({}); -} - -void AbstractStep::setInnerFocus() { - if (_setInnerFocusCallback) { - _setInnerFocusCallback(); - } -} - -bool AbstractStep::isPasswordInvalidError(const QString &type) { - if (type == u"PASSWORD_HASH_INVALID"_q - || type == u"SRP_PASSWORD_CHANGED"_q) { - - // Most likely the cloud password has been changed on another device. - // Quit. - _quits.fire(AbstractStep::Types{ - CloudPasswordStartId(), - CloudPasswordInputId(), - CloudPasswordHintId(), - CloudPasswordEmailId(), - CloudPasswordEmailConfirmId(), - CloudPasswordManageId(), - }); - controller()->show( - Ui::MakeInformBox(tr::lng_cloud_password_expired()), - Ui::LayerOption::CloseOther); - setStepData(StepData()); - showBack(); - return true; - } - return false; -} - -rpl::producer AbstractStep::sectionShowOther() { - return _showOther.events(); -} - -rpl::producer<> AbstractStep::sectionShowBack() { - return _showBack.events(); -} - -rpl::producer> AbstractStep::removeFromStack() { - return rpl::merge(removeTypes(), _quits.events()); -} - -void AbstractStep::setStepDataReference(std::any &data) { - _stepData = &data; -} - -StepData AbstractStep::stepData() const { - if (!_stepData || !_stepData->has_value()) { - StepData(); - } - const auto my = std::any_cast(_stepData); - return my ? (*my) : StepData(); -} - -void AbstractStep::setStepData(StepData data) { - if (_stepData) { - *_stepData = data; - } -} - -AbstractStep::~AbstractStep() = default; - } // namespace Settings::CloudPassword diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.h b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.h index 836728b4821a85..586e58a9dd1ad1 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.h +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_common.h @@ -7,7 +7,7 @@ For license and copyright information please follow this link: */ #pragma once -#include "settings/settings_common_session.h" +#include "ui/text/text_variant.h" #include "ui/widgets/box_content_divider.h" namespace Ui { @@ -43,7 +43,10 @@ struct StepData { ProcessRecover processRecover; }; -void SetupAutoCloseTimer(rpl::lifetime &lifetime, Fn callback); +void SetupAutoCloseTimer( + rpl::lifetime &lifetime, + Fn callback, + Fn lastNonIdleTime); void SetupHeader( not_null content, @@ -102,73 +105,5 @@ class OneEdgeBoxContentDivider : public Ui::BoxContentDivider { }; -class AbstractStep : public AbstractSection { -public: - using Types = std::vector; - AbstractStep( - QWidget *parent, - not_null controller); - ~AbstractStep(); - - void showFinished() override final; - void setInnerFocus() override final; - [[nodiscard]] rpl::producer sectionShowOther() override final; - [[nodiscard]] rpl::producer<> sectionShowBack() override final; - - [[nodiscard]] rpl::producer removeFromStack() override final; - - void setStepDataReference(std::any &data) override; - -protected: - [[nodiscard]] not_null controller() const; - [[nodiscard]] Api::CloudPassword &cloudPassword(); - - [[nodiscard]] virtual rpl::producer removeTypes(); - - bool isPasswordInvalidError(const QString &type); - - void showBack(); - void showOther(Type type); - - void setFocusCallback(Fn callback); - - [[nodiscard]] rpl::producer<> showFinishes() const; - - StepData stepData() const; - void setStepData(StepData data); - -private: - const not_null _controller; - - Fn _setInnerFocusCallback; - - rpl::event_stream<> _showFinished; - rpl::event_stream _showOther; - rpl::event_stream<> _showBack; - rpl::event_stream _quits; - - std::any *_stepData; - -}; - -template -class TypedAbstractStep : public AbstractStep { -public: - using AbstractStep::AbstractStep; - - void setStepDataReference(std::any &data) override final { - AbstractStep::setStepDataReference(data); - static_cast(this)->setupContent(); - } - - [[nodiscard]] static Type Id() { - return SectionFactory::Instance(); - } - [[nodiscard]] Type id() const final override { - return Id(); - } - -}; - } // namespace Settings::CloudPassword diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email.cpp index aead318d0a296e..f83eb143798035 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email.cpp @@ -13,6 +13,7 @@ For license and copyright information please follow this link: #include "settings/cloud_password/settings_cloud_password_common.h" #include "settings/cloud_password/settings_cloud_password_email_confirm.h" #include "settings/cloud_password/settings_cloud_password_manage.h" +#include "settings/cloud_password/settings_cloud_password_step.h" #include "ui/vertical_list.h" #include "ui/boxes/confirm_box.h" #include "ui/widgets/buttons.h" diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email_confirm.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email_confirm.cpp index 7bf21c9d53b940..2e482f76191c92 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email_confirm.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_email_confirm.cpp @@ -19,6 +19,7 @@ For license and copyright information please follow this link: #include "settings/cloud_password/settings_cloud_password_input.h" #include "settings/cloud_password/settings_cloud_password_manage.h" #include "settings/cloud_password/settings_cloud_password_start.h" +#include "settings/cloud_password/settings_cloud_password_step.h" #include "ui/vertical_list.h" #include "ui/boxes/confirm_box.h" #include "ui/text/format_values.h" diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_hint.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_hint.cpp index e690b99051ce9d..7f59c7a9363581 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_hint.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_hint.cpp @@ -12,6 +12,7 @@ For license and copyright information please follow this link: #include "settings/cloud_password/settings_cloud_password_common.h" #include "settings/cloud_password/settings_cloud_password_email.h" #include "settings/cloud_password/settings_cloud_password_manage.h" +#include "settings/cloud_password/settings_cloud_password_step.h" #include "ui/vertical_list.h" #include "ui/widgets/buttons.h" #include "ui/widgets/fields/input_field.h" diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp index b25659f3f8c086..0064dcbda7593e 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp @@ -18,6 +18,7 @@ For license and copyright information please follow this link: #include "settings/cloud_password/settings_cloud_password_email_confirm.h" #include "settings/cloud_password/settings_cloud_password_hint.h" #include "settings/cloud_password/settings_cloud_password_manage.h" +#include "settings/cloud_password/settings_cloud_password_step.h" #include "ui/boxes/confirm_box.h" #include "ui/text/format_values.h" #include "ui/widgets/buttons.h" diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_manage.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_manage.cpp index 2d273895e6e6b5..1f7a876738c888 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_manage.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_manage.cpp @@ -8,6 +8,7 @@ For license and copyright information please follow this link: #include "settings/cloud_password/settings_cloud_password_manage.h" #include "api/api_cloud_password.h" +#include "core/application.h" #include "core/core_cloud_password.h" #include "lang/lang_keys.h" #include "settings/cloud_password/settings_cloud_password_common.h" @@ -16,6 +17,7 @@ For license and copyright information please follow this link: #include "settings/cloud_password/settings_cloud_password_hint.h" #include "settings/cloud_password/settings_cloud_password_input.h" #include "settings/cloud_password/settings_cloud_password_start.h" +#include "settings/cloud_password/settings_cloud_password_step.h" #include "ui/vertical_list.h" #include "ui/boxes/confirm_box.h" #include "ui/widgets/buttons.h" @@ -97,7 +99,10 @@ void Manage::setupContent() { showBack(); }; - SetupAutoCloseTimer(content->lifetime(), quit); + SetupAutoCloseTimer( + content->lifetime(), + quit, + [] { return Core::App().lastNonIdleTime(); }); const auto state = cloudPassword().stateCurrent(); if (!state) { diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_start.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_start.cpp index 00fd0f240ce615..e882a3406bff8c 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_start.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_start.cpp @@ -10,6 +10,7 @@ For license and copyright information please follow this link: #include "lang/lang_keys.h" #include "settings/cloud_password/settings_cloud_password_common.h" #include "settings/cloud_password/settings_cloud_password_input.h" +#include "settings/cloud_password/settings_cloud_password_step.h" #include "ui/vertical_list.h" #include "ui/widgets/buttons.h" #include "ui/wrap/vertical_layout.h" diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_step.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_step.cpp new file mode 100644 index 00000000000000..b9bf6baa197a15 --- /dev/null +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_step.cpp @@ -0,0 +1,126 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "settings/cloud_password/settings_cloud_password_step.h" + +#include "apiwrap.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "settings/cloud_password/settings_cloud_password_common.h" +#include "settings/cloud_password/settings_cloud_password_email.h" +#include "settings/cloud_password/settings_cloud_password_email_confirm.h" +#include "settings/cloud_password/settings_cloud_password_hint.h" +#include "settings/cloud_password/settings_cloud_password_input.h" +#include "settings/cloud_password/settings_cloud_password_manage.h" +#include "settings/cloud_password/settings_cloud_password_start.h" +#include "ui/boxes/confirm_box.h" +#include "window/window_session_controller.h" + +namespace Settings::CloudPassword { + +AbstractStep::AbstractStep( + QWidget *parent, + not_null controller) +: AbstractSection(parent) +, _controller(controller) { +} + +not_null AbstractStep::controller() const { + return _controller; +} + +Api::CloudPassword &AbstractStep::cloudPassword() { + return _controller->session().api().cloudPassword(); +} + +rpl::producer AbstractStep::removeTypes() { + return rpl::never(); +} + +void AbstractStep::showBack() { + _showBack.fire({}); +} + +void AbstractStep::showOther(Type type) { + _showOther.fire_copy(type); +} + +void AbstractStep::setFocusCallback(Fn callback) { + _setInnerFocusCallback = callback; +} + +rpl::producer<> AbstractStep::showFinishes() const { + return _showFinished.events(); +} + +void AbstractStep::showFinished() { + _showFinished.fire({}); +} + +void AbstractStep::setInnerFocus() { + if (_setInnerFocusCallback) { + _setInnerFocusCallback(); + } +} + +bool AbstractStep::isPasswordInvalidError(const QString &type) { + if (type == u"PASSWORD_HASH_INVALID"_q + || type == u"SRP_PASSWORD_CHANGED"_q) { + + // Most likely the cloud password has been changed on another device. + // Quit. + _quits.fire(AbstractStep::Types{ + CloudPasswordStartId(), + CloudPasswordInputId(), + CloudPasswordHintId(), + CloudPasswordEmailId(), + CloudPasswordEmailConfirmId(), + CloudPasswordManageId(), + }); + controller()->show( + Ui::MakeInformBox(tr::lng_cloud_password_expired()), + Ui::LayerOption::CloseOther); + setStepData(StepData()); + showBack(); + return true; + } + return false; +} + +rpl::producer AbstractStep::sectionShowOther() { + return _showOther.events(); +} + +rpl::producer<> AbstractStep::sectionShowBack() { + return _showBack.events(); +} + +rpl::producer> AbstractStep::removeFromStack() { + return rpl::merge(removeTypes(), _quits.events()); +} + +void AbstractStep::setStepDataReference(std::any &data) { + _stepData = &data; +} + +StepData AbstractStep::stepData() const { + if (!_stepData || !_stepData->has_value()) { + StepData(); + } + const auto my = std::any_cast(_stepData); + return my ? (*my) : StepData(); +} + +void AbstractStep::setStepData(StepData data) { + if (_stepData) { + *_stepData = data; + } +} + +AbstractStep::~AbstractStep() = default; + +} // namespace Settings::CloudPassword diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_step.h b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_step.h new file mode 100644 index 00000000000000..2410247852f704 --- /dev/null +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_step.h @@ -0,0 +1,89 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "settings/settings_common_session.h" + +namespace Api { +class CloudPassword; +} // namespace Api + +namespace Settings::CloudPassword { + +struct StepData; + +class AbstractStep : public AbstractSection { +public: + using Types = std::vector; + AbstractStep( + QWidget *parent, + not_null controller); + ~AbstractStep(); + + void showFinished() override final; + void setInnerFocus() override final; + [[nodiscard]] rpl::producer sectionShowOther() override final; + [[nodiscard]] rpl::producer<> sectionShowBack() override final; + + [[nodiscard]] rpl::producer removeFromStack() override final; + + void setStepDataReference(std::any &data) override; + +protected: + [[nodiscard]] not_null controller() const; + [[nodiscard]] Api::CloudPassword &cloudPassword(); + + [[nodiscard]] virtual rpl::producer removeTypes(); + + bool isPasswordInvalidError(const QString &type); + + void showBack(); + void showOther(Type type); + + void setFocusCallback(Fn callback); + + [[nodiscard]] rpl::producer<> showFinishes() const; + + StepData stepData() const; + void setStepData(StepData data); + +private: + const not_null _controller; + + Fn _setInnerFocusCallback; + + rpl::event_stream<> _showFinished; + rpl::event_stream _showOther; + rpl::event_stream<> _showBack; + rpl::event_stream _quits; + + std::any *_stepData; + +}; + +template +class TypedAbstractStep : public AbstractStep { +public: + using AbstractStep::AbstractStep; + + void setStepDataReference(std::any &data) override final { + AbstractStep::setStepDataReference(data); + static_cast(this)->setupContent(); + } + + [[nodiscard]] static Type Id() { + return SectionFactory::Instance(); + } + [[nodiscard]] Type id() const final override { + return Id(); + } + +}; + +} // namespace Settings::CloudPassword + diff --git a/Telegram/SourceFiles/settings/settings_local_passcode.cpp b/Telegram/SourceFiles/settings/settings_local_passcode.cpp index 193445caf3dff5..8f639c30a63e03 100644 --- a/Telegram/SourceFiles/settings/settings_local_passcode.cpp +++ b/Telegram/SourceFiles/settings/settings_local_passcode.cpp @@ -18,6 +18,7 @@ For license and copyright information please follow this link: #include "main/main_domain.h" #include "main/main_session.h" #include "settings/cloud_password/settings_cloud_password_common.h" +#include "settings/cloud_password/settings_cloud_password_step.h" #include "storage/storage_domain.h" #include "ui/vertical_list.h" #include "ui/boxes/confirm_box.h" @@ -128,7 +129,8 @@ void LocalPasscodeEnter::setupContent() { if (isChange) { CloudPassword::SetupAutoCloseTimer( content->lifetime(), - [=] { _showBack.fire({}); }); + [=] { _showBack.fire({}); }, + [] { return Core::App().lastNonIdleTime(); }); } Ui::AddSkip(content); @@ -448,7 +450,8 @@ void LocalPasscodeManage::setupContent() { CloudPassword::SetupAutoCloseTimer( content->lifetime(), - [=] { _showBack.fire({}); }); + [=] { _showBack.fire({}); }, + [] { return Core::App().lastNonIdleTime(); }); Ui::AddSkip(content); diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index e9e683250d007f..77e710a6a01100 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -224,6 +224,8 @@ PRIVATE settings/settings_common.cpp settings/settings_common.h + settings/cloud_password/settings_cloud_password_common.cpp + settings/cloud_password/settings_cloud_password_common.h statistics/chart_lines_filter_controller.cpp statistics/chart_lines_filter_controller.h From 658cb438f8cf3ce239cde461a822448cac721af6 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 8 Jan 2025 11:39:42 +0300 Subject: [PATCH 15/17] Added spoiler entity to email pattern in recover box. --- Telegram/SourceFiles/boxes/passcode_box.cpp | 80 +++++++++++++++------ Telegram/SourceFiles/boxes/passcode_box.h | 6 +- 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/Telegram/SourceFiles/boxes/passcode_box.cpp b/Telegram/SourceFiles/boxes/passcode_box.cpp index 840e4872d44d64..308384e167f336 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.cpp +++ b/Telegram/SourceFiles/boxes/passcode_box.cpp @@ -26,6 +26,7 @@ For license and copyright information please follow this link: #include "ui/widgets/labels.h" #include "ui/wrap/fade_wrap.h" #include "ui/painter.h" +#include "ui/rect.h" #include "passport/passport_encryption.h" #include "passport/passport_panel_edit_contact.h" #include "settings/settings_privacy_security.h" @@ -171,8 +172,9 @@ PasscodeBox::PasscodeBox( bool turningOff) : _session(session) , _api(&_session->mtp()) +, _textWidth(st::boxWidth - st::boxPadding.left() * 1.5) , _turningOff(turningOff) -, _about(st::boxWidth - st::boxPadding.left() * 1.5) +, _about(_textWidth) , _oldPasscode(this, st::defaultInputField, tr::lng_passcode_enter_old()) , _newPasscode( this, @@ -193,10 +195,11 @@ PasscodeBox::PasscodeBox( const CloudFields &fields) : _session(session) , _api(mtp) +, _textWidth(st::boxWidth - st::boxPadding.left() * 1.5) , _turningOff(fields.turningOff) , _cloudPwd(true) , _cloudFields(fields) -, _about(st::boxWidth - st::boxPadding.left() * 1.5) +, _about(_textWidth) , _oldPasscode(this, st::defaultInputField, tr::lng_cloud_password_enter_old()) , _newPasscode( this, @@ -274,7 +277,7 @@ void PasscodeBox::prepare() { : _cloudPwd ? tr::lng_cloud_password_about(tr::now) : tr::lng_passcode_about(tr::now))); - _aboutHeight = _about.countHeight(st::boxWidth - st::boxPadding.left() * 1.5); + _aboutHeight = _about.countHeight(_textWidth); const auto onlyCheck = onlyCheckCurrent(); if (onlyCheck) { _oldPasscode->show(); @@ -382,28 +385,27 @@ void PasscodeBox::paintEvent(QPaintEvent *e) { Painter p(this); - int32 w = st::boxWidth - st::boxPadding.left() * 1.5; int32 abouty = (_passwordHint->isHidden() ? ((_reenterPasscode->isHidden() ? (_oldPasscode->y() + (_showRecoverLink && !_hintText.isEmpty() ? st::passcodeTextLine : 0)) : _reenterPasscode->y()) + st::passcodeSkip) : _passwordHint->y()) + _oldPasscode->height() + st::passcodeLittleSkip + st::passcodeAboutSkip; p.setPen(st::boxTextFg); - _about.drawLeft(p, st::boxPadding.left(), abouty, w, width()); + _about.drawLeft(p, st::boxPadding.left(), abouty, _textWidth, width()); if (!_hintText.isEmpty() && _oldError.isEmpty()) { - _hintText.drawLeftElided(p, st::boxPadding.left(), _oldPasscode->y() + _oldPasscode->height() + ((st::passcodeTextLine - st::normalFont->height) / 2), w, width(), 1, style::al_topleft); + _hintText.drawLeftElided(p, st::boxPadding.left(), _oldPasscode->y() + _oldPasscode->height() + ((st::passcodeTextLine - st::normalFont->height) / 2), _textWidth, width(), 1, style::al_topleft); } if (!_oldError.isEmpty()) { p.setPen(st::boxTextFgError); - p.drawText(QRect(st::boxPadding.left(), _oldPasscode->y() + _oldPasscode->height(), w, st::passcodeTextLine), _oldError, style::al_left); + p.drawText(QRect(st::boxPadding.left(), _oldPasscode->y() + _oldPasscode->height(), _textWidth, st::passcodeTextLine), _oldError, style::al_left); } if (!_newError.isEmpty()) { p.setPen(st::boxTextFgError); - p.drawText(QRect(st::boxPadding.left(), _reenterPasscode->y() + _reenterPasscode->height(), w, st::passcodeTextLine), _newError, style::al_left); + p.drawText(QRect(st::boxPadding.left(), _reenterPasscode->y() + _reenterPasscode->height(), _textWidth, st::passcodeTextLine), _newError, style::al_left); } if (!_emailError.isEmpty()) { p.setPen(st::boxTextFgError); - p.drawText(QRect(st::boxPadding.left(), _recoverEmail->y() + _recoverEmail->height(), w, st::passcodeTextLine), _emailError, style::al_left); + p.drawText(QRect(st::boxPadding.left(), _recoverEmail->y() + _recoverEmail->height(), _textWidth, st::passcodeTextLine), _emailError, style::al_left); } } @@ -1141,11 +1143,21 @@ RecoverBox::RecoverBox( Fn closeParent) : _session(session) , _api(mtp) -, _pattern(st::normalFont->elided(tr::lng_signin_recover_hint(tr::now, lt_recover_email, pattern), st::boxWidth - st::boxPadding.left() * 1.5)) +, _textWidth(st::boxWidth - st::boxPadding.left() * 1.5) , _cloudFields(fields) , _recoverCode(this, st::defaultInputField, tr::lng_signin_code()) , _noEmailAccess(this, tr::lng_signin_try_password(tr::now)) +, _patternLabel( + this, + tr::lng_signin_recover_hint( + lt_recover_email, + rpl::single(Ui::Text::WrapEmailPattern(pattern)), + Ui::Text::WithEntities), + st::termsContent, + st::defaultPopupMenu, + [=](Fn update) { return CommonTextContext{ std::move(update) }; }) , _closeParent(std::move(closeParent)) { + _patternLabel->setAttribute(Qt::WA_TransparentForMouseEvents); if (_cloudFields.pendingResetDate != 0 || !session) { _noEmailAccess.destroy(); } else { @@ -1176,19 +1188,24 @@ rpl::producer<> RecoverBox::recoveryExpired() const { return _recoveryExpired.events(); } -void RecoverBox::prepare() { - setTitle(tr::lng_signin_recover_title()); - - addButton(tr::lng_passcode_submit(), [=] { submit(); }); - addButton(tr::lng_cancel(), [=] { closeBox(); }); - +void RecoverBox::updateHeight() { setDimensions( st::boxWidth, (st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine + _recoverCode->height() + + _patternLabel->height() + st::passcodeTextLine)); +} + +void RecoverBox::prepare() { + setTitle(tr::lng_signin_recover_title()); + + addButton(tr::lng_passcode_submit(), [=] { submit(); }); + addButton(tr::lng_cancel(), [=] { closeBox(); }); + + updateHeight(); _recoverCode->changes( ) | rpl::start_with_next([=] { @@ -1205,23 +1222,42 @@ void RecoverBox::paintEvent(QPaintEvent *e) { p.setFont(st::normalFont); p.setPen(st::boxTextFg); - int32 w = st::boxWidth - st::boxPadding.left() * 1.5; - p.drawText(QRect(st::boxPadding.left(), _recoverCode->y() - st::passcodeTextLine - st::passcodePadding.top(), w, st::passcodePadding.top() + st::passcodeTextLine), _pattern, style::al_left); if (!_error.isEmpty()) { p.setPen(st::boxTextFgError); - p.drawText(QRect(st::boxPadding.left(), _recoverCode->y() + _recoverCode->height(), w, st::passcodeTextLine), _error, style::al_left); + p.drawText( + QRect( + st::boxPadding.left(), + _recoverCode->y() + _recoverCode->height(), + _textWidth, + st::passcodeTextLine), + _error, + style::al_left); } } void RecoverBox::resizeEvent(QResizeEvent *e) { BoxContent::resizeEvent(e); - _recoverCode->resize(st::boxWidth - st::boxPadding.left() - st::boxPadding.right(), _recoverCode->height()); - _recoverCode->moveToLeft(st::boxPadding.left(), st::passcodePadding.top() + st::passcodePadding.bottom() + st::passcodeTextLine); + _patternLabel->resizeToWidth(_textWidth); + _patternLabel->moveToLeft( + st::boxPadding.left(), + st::passcodePadding.top()); + + _recoverCode->resize( + st::boxWidth - st::boxPadding.left() - st::boxPadding.right(), + _recoverCode->height()); + _recoverCode->moveToLeft( + st::boxPadding.left(), + rect::m::sum::v(st::passcodePadding) + _patternLabel->height()); if (_noEmailAccess) { - _noEmailAccess->moveToLeft(st::boxPadding.left(), _recoverCode->y() + _recoverCode->height() + (st::passcodeTextLine - _noEmailAccess->height()) / 2); + _noEmailAccess->moveToLeft( + st::boxPadding.left(), + rect::bottom(_recoverCode) + + (st::passcodeTextLine - _noEmailAccess->height()) / 2); } + + updateHeight(); } void RecoverBox::setInnerFocus() { diff --git a/Telegram/SourceFiles/boxes/passcode_box.h b/Telegram/SourceFiles/boxes/passcode_box.h index b651cda64a8580..09f3335617b7e0 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.h +++ b/Telegram/SourceFiles/boxes/passcode_box.h @@ -154,6 +154,7 @@ class PasscodeBox : public Ui::BoxContent { Main::Session *_session = nullptr; MTP::Sender _api; + const int _textWidth; QString _pattern; @@ -219,17 +220,18 @@ class RecoverBox final : public Ui::BoxContent { void proceedToChange(const QString &code); void checkSubmitFail(const MTP::Error &error); void setError(const QString &error); + void updateHeight(); Main::Session *_session = nullptr; MTP::Sender _api; + const int _textWidth; mtpRequestId _submitRequest = 0; - QString _pattern; - PasscodeBox::CloudFields _cloudFields; object_ptr _recoverCode; object_ptr _noEmailAccess; + object_ptr _patternLabel; Fn _closeParent; QString _error; From 1ac33d30bdad181dfb18bef172ba0220fab7e375 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 8 Jan 2025 17:36:25 +0400 Subject: [PATCH 16/17] Version 5.10.2: Improve gifts layout. --- Telegram/SourceFiles/boxes/star_gift_box.cpp | 120 +++++++++++------- Telegram/SourceFiles/boxes/star_gift_box.h | 9 ++ .../view/media/history_view_premium_gift.cpp | 5 +- .../view/media/history_view_unique_gift.cpp | 11 +- .../peer_gifts/info_peer_gifts_common.cpp | 51 ++++++-- .../info/peer_gifts/info_peer_gifts_common.h | 5 +- .../settings/settings_credits_graphics.cpp | 1 + Telegram/SourceFiles/ui/effects/credits.style | 6 +- 8 files changed, 144 insertions(+), 64 deletions(-) diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index 74cbfd4dbfb869..2ba9fddc23c08b 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -298,48 +298,6 @@ auto GenerateGiftMedia( }; } -struct PatternPoint { - QPointF position; - float64 scale = 1.; - float64 opacity = 1.; -}; -[[nodiscard]] const std::vector &PatternPoints() { - static const auto kSmall = 0.7; - static const auto kFaded = 0.3; - static const auto kLarge = 0.85; - static const auto kOpaque = 0.5; - static const auto result = std::vector{ - { { 0.5, 0.066 }, kSmall, kFaded }, - - { { 0.177, 0.168 }, kSmall, kFaded }, - { { 0.822, 0.168 }, kSmall, kFaded }, - - { { 0.37, 0.168 }, kLarge, kOpaque }, - { { 0.63, 0.168 }, kLarge, kOpaque }, - - { { 0.277, 0.308 }, kSmall, kOpaque }, - { { 0.723, 0.308 }, kSmall, kOpaque }, - - { { 0.13, 0.42 }, kSmall, kFaded }, - { { 0.87, 0.42 }, kSmall, kFaded }, - - { { 0.27, 0.533 }, kLarge, kOpaque }, - { { 0.73, 0.533 }, kLarge, kOpaque }, - - { { 0.2, 0.73 }, kSmall, kFaded }, - { { 0.8, 0.73 }, kSmall, kFaded }, - - { { 0.302, 0.825 }, kLarge, kOpaque }, - { { 0.698, 0.825 }, kLarge, kOpaque }, - - { { 0.5, 0.876 }, kLarge, kFaded }, - - { { 0.144, 0.936 }, kSmall, kFaded }, - { { 0.856, 0.936 }, kSmall, kFaded }, - }; - return result; -} - [[nodiscard]] QImage CreateGradient( QSize size, const Data::UniqueGift &gift) { @@ -2108,6 +2066,7 @@ void AddUniqueGiftCover( PaintPoints( p, + PatternPoints(), gift.emojis, gift.emoji.get(), *gift.gift, @@ -2383,8 +2342,83 @@ void UpgradeBox( AddUniqueCloseButton(box); } +const std::vector &PatternPoints() { + static const auto kSmall = 0.7; + static const auto kFaded = 0.2; + static const auto kLarge = 0.85; + static const auto kOpaque = 0.3; + static const auto result = std::vector{ + { { 0.5, 0.066 }, kSmall, kFaded }, + + { { 0.177, 0.168 }, kSmall, kFaded }, + { { 0.822, 0.168 }, kSmall, kFaded }, + + { { 0.37, 0.168 }, kLarge, kOpaque }, + { { 0.63, 0.168 }, kLarge, kOpaque }, + + { { 0.277, 0.308 }, kSmall, kOpaque }, + { { 0.723, 0.308 }, kSmall, kOpaque }, + + { { 0.13, 0.42 }, kSmall, kFaded }, + { { 0.87, 0.42 }, kSmall, kFaded }, + + { { 0.27, 0.533 }, kLarge, kOpaque }, + { { 0.73, 0.533 }, kLarge, kOpaque }, + + { { 0.2, 0.73 }, kSmall, kFaded }, + { { 0.8, 0.73 }, kSmall, kFaded }, + + { { 0.302, 0.825 }, kLarge, kOpaque }, + { { 0.698, 0.825 }, kLarge, kOpaque }, + + { { 0.5, 0.876 }, kLarge, kFaded }, + + { { 0.144, 0.936 }, kSmall, kFaded }, + { { 0.856, 0.936 }, kSmall, kFaded }, + }; + return result; +} + +const std::vector &PatternPointsSmall() { + static const auto kSmall = 0.45; + static const auto kFaded = 0.2; + static const auto kLarge = 0.55; + static const auto kOpaque = 0.3; + static const auto result = std::vector{ + { { 0.5, 0.066 }, kSmall, kFaded }, + + { { 0.177, 0.168 }, kSmall, kFaded }, + { { 0.822, 0.168 }, kSmall, kFaded }, + + { { 0.37, 0.168 }, kLarge, kOpaque }, + { { 0.63, 0.168 }, kLarge, kOpaque }, + + { { 0.277, 0.308 }, kSmall, kOpaque }, + { { 0.723, 0.308 }, kSmall, kOpaque }, + + { { 0.13, 0.42 }, kSmall, kFaded }, + { { 0.87, 0.42 }, kSmall, kFaded }, + + { { 0.27, 0.533 }, kLarge, kOpaque }, + { { 0.73, 0.533 }, kLarge, kOpaque }, + + { { 0.2, 0.73 }, kSmall, kFaded }, + { { 0.8, 0.73 }, kSmall, kFaded }, + + { { 0.302, 0.825 }, kLarge, kOpaque }, + { { 0.698, 0.825 }, kLarge, kOpaque }, + + { { 0.5, 0.876 }, kLarge, kFaded }, + + { { 0.144, 0.936 }, kSmall, kFaded }, + { { 0.856, 0.936 }, kSmall, kFaded }, + }; + return result; +} + void PaintPoints( QPainter &p, + const std::vector &points, base::flat_map &cache, not_null emoji, const Data::UniqueGift &gift, @@ -2417,7 +2451,7 @@ void PaintPoints( } } }; - for (const auto point : PatternPoints()) { + for (const auto &point : points) { paintPoint(point); } } diff --git a/Telegram/SourceFiles/boxes/star_gift_box.h b/Telegram/SourceFiles/boxes/star_gift_box.h index dc85a0019d523d..bacb3997d3700a 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.h +++ b/Telegram/SourceFiles/boxes/star_gift_box.h @@ -42,8 +42,17 @@ void AddUniqueGiftCover( rpl::producer data, rpl::producer subtitleOverride = nullptr); +struct PatternPoint { + QPointF position; + float64 scale = 1.; + float64 opacity = 1.; +}; +[[nodiscard]] const std::vector &PatternPoints(); +[[nodiscard]] const std::vector &PatternPointsSmall(); + void PaintPoints( QPainter &p, + const std::vector &points, base::flat_map &cache, not_null emoji, const Data::UniqueGift &gift, diff --git a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp index 0a17cca84a0266..f7d94fe67e4d46 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp @@ -312,7 +312,8 @@ QImage PremiumGift::cornerTag(const PaintContext &context) { if (_data.unique) { badge = { .text = tr::lng_gift_collectible_tag(tr::now), - .bg = _data.unique->backdrop.patternColor, + .bg1 = _data.unique->backdrop.edgeColor, + .bg2 = _data.unique->backdrop.patternColor, .fg = QColor(255, 255, 255), }; } else if (const auto count = _data.limitedCount) { @@ -325,7 +326,7 @@ QImage PremiumGift::cornerTag(const PaintContext &context) { (((count % 1000) && (count < 10'000)) ? Lang::FormatCountDecimal(count) : Lang::FormatCountToShort(count).string))), - .bg = context.st->msgServiceBg()->c, + .bg1 = context.st->msgServiceBg()->c, .fg = context.st->msgServiceFg()->c, }; } else { diff --git a/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp b/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp index a41e867d04ca25..c2db18f8d9eccb 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp @@ -525,7 +525,13 @@ Fn UniqueGiftBg( const auto doubled = width + 2 * shift; const auto outer = QRect(-shift, -shift, doubled, doubled); p.setClipRect(inner); - Ui::PaintPoints(p, state->cache, state->pattern.get(), *gift, outer); + Ui::PaintPoints( + p, + Ui::PatternPoints(), + state->cache, + state->pattern.get(), + *gift, + outer); p.setClipping(false); const auto add = style::ConvertScale(2); @@ -536,7 +542,8 @@ Fn UniqueGiftBg( inner.height() + 2 * add); auto badge = Info::PeerGifts::GiftBadge{ .text = tr::lng_gift_collectible_tag(tr::now), - .bg = gift->backdrop.patternColor, + .bg1 = gift->backdrop.edgeColor, + .bg2 = gift->backdrop.patternColor, .fg = gift->backdrop.textColor, }; if (state->badgeCache.isNull() || state->badgeKey != badge) { diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp index eded8840931451..54c7cc007fdbb4 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp @@ -42,10 +42,14 @@ std::strong_ordering operator<=>(const GiftBadge &a, const GiftBadge &b) { if (result1 != std::strong_ordering::equal) { return result1; } - const auto result2 = (a.bg.rgb() <=> b.bg.rgb()); + const auto result2 = (a.bg1.rgb() <=> b.bg1.rgb()); if (result2 != std::strong_ordering::equal) { return result2; } + const auto result3 = (a.bg2.rgb() <=> b.bg2.rgb()); + if (result3 != std::strong_ordering::equal) { + return result3; + } return a.fg.rgb() <=> b.fg.rgb(); } @@ -148,6 +152,7 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) { if (mode != Mode::Full) { _button = QRect(); + _small = true; return; } const auto buttonw = _price.maxWidth(); @@ -263,11 +268,11 @@ void GiftButton::cacheUniqueBackground( if (!_patterned && _uniquePatternEmoji->ready()) { _patterned = true; auto p = QPainter(&_uniqueBackgroundCache); - p.setOpacity(0.5); p.setClipRect(inner); const auto skip = inner.width() / 3; Ui::PaintPoints( p, + Ui::PatternPointsSmall(), _uniquePatternCache, _uniquePatternEmoji.get(), *unique, @@ -338,7 +343,9 @@ void GiftButton::paintEvent(QPaintEvent *e) { p.drawImage( QRect( (width - size.width()) / 2, - (_text.isEmpty() + (_small + ? st::giftBoxSmallStickerTop + : _text.isEmpty() ? st::giftBoxStickerStarTop : st::giftBoxStickerTop), size.width(), @@ -348,7 +355,9 @@ void GiftButton::paintEvent(QPaintEvent *e) { if (hidden) { const auto topleft = QPoint( (width - st::giftBoxStickerSize.width()) / 2, - (_text.isEmpty() + (_small + ? st::giftBoxSmallStickerTop + : _text.isEmpty() ? st::giftBoxStickerStarTop : st::giftBoxStickerTop)); _delegate->hiddenMark()->paint( @@ -372,8 +381,9 @@ void GiftButton::paintEvent(QPaintEvent *e) { const auto kMinus = QChar(0x2212); return GiftBadge{ .text = kMinus + QString::number(data.discountPercent) + '%', - .bg = st::attentionButtonFg->c, + .bg1 = st::attentionButtonFg->c, .fg = st::windowBg->c, + .small = true, }; } return GiftBadge(); @@ -383,7 +393,7 @@ void GiftButton::paintEvent(QPaintEvent *e) { return GiftBadge{ .text = (soldOut ? tr::lng_gift_stars_sold_out(tr::now) - : !data.userpic + : (!data.userpic && !data.info.unique) ? tr::lng_gift_stars_limited(tr::now) : (count == 1) ? tr::lng_gift_limited_of_one(tr::now) @@ -393,19 +403,23 @@ void GiftButton::paintEvent(QPaintEvent *e) { (((count % 1000) && (count < 10'000)) ? Lang::FormatCountDecimal(count) : Lang::FormatCountToShort(count).string))), - .bg = (unique - ? unique->backdrop.patternColor + .bg1 = (unique + ? unique->backdrop.edgeColor : soldOut ? st::attentionButtonFg->c : st::windowActiveTextFg->c), + .bg2 = (unique + ? unique->backdrop.patternColor + : QColor(0, 0, 0, 0)), .fg = unique ? QColor(255, 255, 255) : st::windowBg->c, + .small = true, }; } return GiftBadge(); }); if (badge) { - const auto rubberOut = _extend.top(); + const auto rubberOut = st::lineWidth; const auto inner = rect().marginsRemoved(_extend); p.setClipRect(inner.marginsAdded( { rubberOut, rubberOut, rubberOut, rubberOut })); @@ -413,8 +427,8 @@ void GiftButton::paintEvent(QPaintEvent *e) { const auto cached = _delegate->cachedBadge(badge); const auto width = cached.width() / cached.devicePixelRatio(); p.drawImage( - position.x() + singlew + _extend.top() - width, - position.y() - _extend.top(), + position.x() + singlew + rubberOut - width, + position.y() - rubberOut, cached); } if (!_button.isEmpty()) { @@ -633,7 +647,9 @@ rpl::producer> GiftStickerValue( } QImage ValidateRotatedBadge(const GiftBadge &badge, int added) { - const auto &font = st::semiboldFont; + const auto &font = badge.small + ? st::giftBoxGiftBadgeFont + : st::semiboldFont; const auto twidth = font->width(badge.text) + 2 * added; const auto skip = int(std::ceil(twidth / M_SQRT2)); const auto ratio = style::DevicePixelRatio(); @@ -670,12 +686,19 @@ QImage ValidateRotatedBadge(const GiftBadge &badge, int added) { auto p = QPainter(&result); auto hq = PainterHighQualityEnabler(p); p.setPen(Qt::NoPen); - p.setBrush(badge.bg); + p.setBrush(badge.bg1); p.save(); p.translate(textpos); p.rotate(45.); - p.drawRect(-5 * twidth, 0, twidth * 12, font->height); + const auto rect = QRect(-5 * twidth, 0, twidth * 12, font->height); + p.drawRect(rect); + if (badge.bg2.alpha() > 0) { + p.setOpacity(0.5); + p.setBrush(badge.bg2); + p.drawRect(rect); + p.setOpacity(1.); + } p.restore(); p.drawImage(0, 0, scaled); diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h index bf02e9e2659344..faab730ef5254c 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h @@ -74,8 +74,10 @@ struct GiftDescriptor : std::variant { struct GiftBadge { QString text; - QColor bg; + QColor bg1; + QColor bg2 = QColor(0, 0, 0, 0); QColor fg; + bool small = false; explicit operator bool() const { return !text.isEmpty(); @@ -148,6 +150,7 @@ class GiftButton final : public Ui::AbstractButton { std::optional _stars; bool _subscribed = false; bool _patterned = false; + bool _small = false; QRect _button; QMargins _extend; diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index fdd757525aac52..98ada1547228a3 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -1348,6 +1348,7 @@ void ReceiptCreditsBox( }; const auto canUpgrade = e.stargiftId && e.canUpgradeGift + && (e.in || giftToSelf) && !e.uniqueGift; const auto canUpgradeFree = canUpgrade && (e.starsUpgradedBySender > 0); diff --git a/Telegram/SourceFiles/ui/effects/credits.style b/Telegram/SourceFiles/ui/effects/credits.style index 15e27eec72e1a5..d8390fe126b0d1 100644 --- a/Telegram/SourceFiles/ui/effects/credits.style +++ b/Telegram/SourceFiles/ui/effects/credits.style @@ -109,11 +109,12 @@ giftBoxTabStyle: semiboldTextStyle; giftBoxTabFg: windowSubTextFg; giftBoxTabFgActive: windowBoldFg; giftBoxTabBgActive: windowBgRipple; -giftBoxPadding: margins(20px, 4px, 20px, 24px); +giftBoxPadding: margins(11px, 4px, 11px, 24px); giftBoxGiftSkip: point(10px, 8px); giftBoxGiftHeight: 164px; -giftBoxGiftSmall: 124px; +giftBoxGiftSmall: 108px; giftBoxGiftRadius: 12px; +giftBoxGiftBadgeFont: font(10px semibold); giftBoxPremiumIconSize: 64px; giftBoxPremiumIconTop: 10px; giftBoxPremiumTextTop: 84px; @@ -125,6 +126,7 @@ giftBoxPreviewTextPadding: margins(12px, 4px, 12px, 4px); giftBoxButtonMargin: margins(12px, 8px, 12px, 12px); giftBoxStickerTop: 0px; giftBoxStickerStarTop: 24px; +giftBoxSmallStickerTop: 16px; giftBoxStickerSize: size(80px, 80px); giftBoxUserpicSize: 24px; giftBoxUserpicSkip: 2px; From 277d76df3ed289b0f63d321eeaf8851e15f9c96a Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 8 Jan 2025 17:42:51 +0400 Subject: [PATCH 17/17] Version 5.10.2: Update Qt patches on Linux. --- Telegram/build/docker/centos_env/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/build/docker/centos_env/Dockerfile b/Telegram/build/docker/centos_env/Dockerfile index 260398d9b2416e..1873cc789f5821 100644 --- a/Telegram/build/docker/centos_env/Dockerfile +++ b/Telegram/build/docker/centos_env/Dockerfile @@ -42,7 +42,7 @@ FROM builder AS patches RUN git init patches \ && cd patches \ && git remote add origin {{ GIT }}/desktop-app/patches.git \ - && git fetch --depth=1 origin cf3b896e00c288143fce51862dbd9b1c86df1960 \ + && git fetch --depth=1 origin 748e206a977d7bd9fb6ed5081515b724e9bc58a0 \ && git reset --hard FETCH_HEAD \ && rm -rf .git