From 2ef8136308e31e07988ee4654b73ae2a5ab495dc Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Sat, 6 Jan 2024 12:56:19 +0400 Subject: [PATCH 01/73] Update patches commit in Dockerfile --- 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 d2c6320a0..bad748eb1 100644 --- a/Telegram/build/docker/centos_env/Dockerfile +++ b/Telegram/build/docker/centos_env/Dockerfile @@ -54,7 +54,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 1e6c830a66649a60a2a277015143260f5716517b \ + && git fetch --depth=1 origin aadb3de1f4b259d64c6a9133fbd2931508a00faa \ && git reset --hard FETCH_HEAD \ && rm -rf .git From 30d5b7fd6651eb1425e77e83edf0b75f645068e2 Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Mon, 8 Jan 2024 16:16:22 +0400 Subject: [PATCH 02/73] Update patches commit in Dockerfile --- 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 bad748eb1..c9031a76d 100644 --- a/Telegram/build/docker/centos_env/Dockerfile +++ b/Telegram/build/docker/centos_env/Dockerfile @@ -54,7 +54,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 aadb3de1f4b259d64c6a9133fbd2931508a00faa \ + && git fetch --depth=1 origin 4ff99fa2d8836f2cd9befe6cf38ce87dc20f276b \ && git reset --hard FETCH_HEAD \ && rm -rf .git From 893e14cc395d6358be84889eefe00fa506e7ef26 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Mon, 8 Jan 2024 17:34:08 +0400 Subject: [PATCH 03/73] Fix payment field values formatting. Regression was introduced in e6b9a07163. Fixes #27318. --- Telegram/SourceFiles/payments/ui/payments_field.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/payments/ui/payments_field.cpp b/Telegram/SourceFiles/payments/ui/payments_field.cpp index e182714e3..1314674ce 100644 --- a/Telegram/SourceFiles/payments/ui/payments_field.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_field.cpp @@ -217,10 +217,10 @@ struct SimpleFieldState { const FieldConfig &config, const QString &parsed, const QString &countryIso2) { - static const auto RegExp = QRegularExpression("[^0-9]\\."); if (config.type == FieldType::Country) { return countryIso2; } else if (config.type == FieldType::Money) { + static const auto RegExp = QRegularExpression("[^0-9\\.]"); const auto rule = LookupCurrencyRule(config.currency); const auto real = QString(parsed).replace( QChar(rule.decimal), @@ -236,6 +236,7 @@ struct SimpleFieldState { int64(base::SafeRound(real * std::pow(10., rule.exponent)))); } else if (config.type == FieldType::CardNumber || config.type == FieldType::CardCVC) { + static const auto RegExp = QRegularExpression("[^0-9]"); return QString(parsed).replace(RegExp, QString()); } return parsed; From c257b75a667acb597e3c7d4e58d809c8fc1775ce Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Fri, 5 Jan 2024 12:05:16 +0400 Subject: [PATCH 04/73] Add poll creation to the attach menu. --- .../inline_bots/bot_attach_web_view.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp index 1a2703675..da0b08d7e 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp @@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/painter.h" #include "window/themes/window_theme.h" #include "window/window_controller.h" +#include "window/window_peer_menu.h" #include "window/window_session_controller.h" #include "webview/webview_interface.h" #include "core/application.h" @@ -1660,6 +1661,28 @@ std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu( attach(false); }, &st::menuIconFile); } + if (peer->canCreatePolls()) { + ++minimal; + raw->addAction(tr::lng_polls_create(tr::now), [=] { + const auto action = actionFactory(); + const auto source = action.options.scheduled + ? Api::SendType::Scheduled + : Api::SendType::Normal; + const auto sendMenuType = action.replyTo.topicRootId + ? SendMenu::Type::SilentOnly + : SendMenu::Type::Scheduled; + const auto flag = PollData::Flags(); + const auto replyTo = action.replyTo; + Window::PeerMenuCreatePoll( + controller, + peer, + replyTo, + flag, + flag, + source, + sendMenuType); + }, &st::menuIconCreatePoll); + } for (const auto &bot : bots->attachBots()) { if (!bot.inAttachMenu || !PeerMatchesTypes(peer, bot.user, bot.types)) { From 28b43eff7c3937bc1d0ce10a974311b6a93f3961 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Fri, 5 Jan 2024 12:50:04 +0400 Subject: [PATCH 05/73] Make Ctrl+Shift+[1-6] jump through accounts. --- Telegram/SourceFiles/core/shortcuts.cpp | 15 +++++++ Telegram/SourceFiles/core/shortcuts.h | 16 ++++++++ .../window/window_session_controller.cpp | 39 ++++++++++++++++--- .../window/window_session_controller.h | 2 +- 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/core/shortcuts.cpp b/Telegram/SourceFiles/core/shortcuts.cpp index f673aba28..56158e2b5 100644 --- a/Telegram/SourceFiles/core/shortcuts.cpp +++ b/Telegram/SourceFiles/core/shortcuts.cpp @@ -80,6 +80,13 @@ const auto CommandByName = base::flat_map<QString, Command>{ { u"next_folder"_q , Command::FolderNext }, { u"all_chats"_q , Command::ShowAllChats }, + { u"account1"_q , Command::ShowAccount1 }, + { u"account2"_q , Command::ShowAccount2 }, + { u"account3"_q , Command::ShowAccount3 }, + { u"account4"_q , Command::ShowAccount4 }, + { u"account5"_q , Command::ShowAccount5 }, + { u"account6"_q , Command::ShowAccount6 }, + { u"folder1"_q , Command::ShowFolder1 }, { u"folder2"_q , Command::ShowFolder2 }, { u"folder3"_q , Command::ShowFolder3 }, @@ -392,6 +399,14 @@ void Manager::fillDefaults() { set(u"%1+%2"_q.arg(ctrl).arg(index), command); } + auto &&accounts = ranges::views::zip( + kShowAccount, + ranges::views::ints(1, ranges::unreachable)); + + for (const auto [command, index] : accounts) { + set(u"%1+shift+%2"_q.arg(ctrl).arg(index), command); + } + set(u"%1+shift+down"_q.arg(ctrl), Command::FolderNext); set(u"%1+shift+up"_q.arg(ctrl), Command::FolderPrevious); diff --git a/Telegram/SourceFiles/core/shortcuts.h b/Telegram/SourceFiles/core/shortcuts.h index d7b3dc3c5..b562517d5 100644 --- a/Telegram/SourceFiles/core/shortcuts.h +++ b/Telegram/SourceFiles/core/shortcuts.h @@ -38,6 +38,13 @@ enum class Command { ChatPinned7, ChatPinned8, + ShowAccount1, + ShowAccount2, + ShowAccount3, + ShowAccount4, + ShowAccount5, + ShowAccount6, + ShowAllChats, ShowFolder1, ShowFolder2, @@ -79,6 +86,15 @@ enum class Command { Command::ShowFolderLast, }; +[[maybe_unused]] constexpr auto kShowAccount = { + Command::ShowAccount1, + Command::ShowAccount2, + Command::ShowAccount3, + Command::ShowAccount4, + Command::ShowAccount5, + Command::ShowAccount6, +}; + [[nodiscard]] FnMut<bool()> RequestHandler(Command command); class Request { diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 454e525f6..3f78e1850 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -1224,19 +1224,48 @@ void SessionController::showGiftPremiumsBox(const QString &ref) { void SessionController::init() { if (session().supportMode()) { - initSupportMode(); + session().supportHelper().registerWindow(this); } + setupShortcuts(); } -void SessionController::initSupportMode() { - session().supportHelper().registerWindow(this); - +void SessionController::setupShortcuts() { Shortcuts::Requests( ) | rpl::filter([=] { - return (Core::App().activeWindow() == &window()); + return (Core::App().activeWindow() == &window()) + && !isLayerShown() + && !window().locked(); }) | rpl::start_with_next([=](not_null<Shortcuts::Request*> request) { using C = Shortcuts::Command; + const auto app = &Core::App(); + const auto accountsCount = int(app->domain().accounts().size()); + auto &&accounts = ranges::views::zip( + Shortcuts::kShowAccount, + ranges::views::ints(0, accountsCount)); + for (const auto [command, index] : accounts) { + request->check(command) && request->handle([=] { + const auto list = app->domain().orderedAccounts(); + if (index >= list.size()) { + return false; + } + const auto account = list[index]; + if (account == &session().account()) { + return false; + } + const auto window = app->separateWindowForAccount(account); + if (window) { + window->activate(); + } else { + app->domain().maybeActivate(account); + } + return true; + }); + } + + if (!session().supportMode()) { + return; + } request->check(C::SupportHistoryBack) && request->handle([=] { return chatEntryHistoryMove(-1); }); diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 03a60fcac..4ef7b1791 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -601,7 +601,7 @@ private: struct CachedTheme; void init(); - void initSupportMode(); + void setupShortcuts(); void refreshFiltersMenu(); void checkOpenedFilter(); void suggestArchiveAndMute(); From 0f207faa3eac0ce4d3eb628a4e243050df069e53 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Mon, 8 Jan 2024 17:47:03 +0400 Subject: [PATCH 06/73] Version 4.14.4. - Switch between logged in accounts using Ctrl+Shift+[1-6] shortcuts. - Add poll creation in groups to the attach menu, if exists. - Another fix for payment card validation. --- 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 | 6 ++++++ 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index bc517dc13..8030e5cba 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ <Identity Name="TelegramMessengerLLP.TelegramDesktop" ProcessorArchitecture="ARCHITECTURE" Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A" - Version="4.14.3.0" /> + Version="4.14.4.0" /> <Properties> <DisplayName>Telegram Desktop</DisplayName> <PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName> diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index ec675b7e3..158616895 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 4,14,3,0 - PRODUCTVERSION 4,14,3,0 + FILEVERSION 4,14,4,0 + PRODUCTVERSION 4,14,4,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "4.14.3.0" + VALUE "FileVersion", "4.14.4.0" VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.14.3.0" + VALUE "ProductVersion", "4.14.4.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 26208ac82..bfc6ab89c 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 4,14,3,0 - PRODUCTVERSION 4,14,3,0 + FILEVERSION 4,14,4,0 + PRODUCTVERSION 4,14,4,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", "4.14.3.0" + VALUE "FileVersion", "4.14.4.0" VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.14.3.0" + VALUE "ProductVersion", "4.14.4.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 939e36683..d6e18ed78 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 = 4014003; -constexpr auto AppVersionStr = "4.14.3"; +constexpr auto AppVersion = 4014004; +constexpr auto AppVersionStr = "4.14.4"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index beba60eed..7f191e54d 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 4014003 +AppVersion 4014004 AppVersionStrMajor 4.14 -AppVersionStrSmall 4.14.3 -AppVersionStr 4.14.3 +AppVersionStrSmall 4.14.4 +AppVersionStr 4.14.4 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 4.14.3 +AppVersionOriginal 4.14.4 diff --git a/changelog.txt b/changelog.txt index da9a23547..06857dfac 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,9 @@ +4.14.4 (08.01.24) + +- Switch between logged in accounts using Ctrl+Shift+[1-6] shortcuts. +- Add poll creation in groups to the attach menu, if exists. +- Another fix for payment card validation. + 4.14.3 (04.01.24) - Allow sending single-time voice messages. From 6b44143f5b93f85fb2c479fe970f7efef5ef9c8a Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Mon, 8 Jan 2024 12:03:49 -0800 Subject: [PATCH 07/73] Version 4.14.4: Fix build with GCC. --- Telegram/SourceFiles/api/api_sending.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp index d971a03f4..0e5d7c585 100644 --- a/Telegram/SourceFiles/api/api_sending.cpp +++ b/Telegram/SourceFiles/api/api_sending.cpp @@ -402,7 +402,6 @@ void SendConfirmedFile( flags |= MessageFlag::HasReplyInfo; } const auto anonymousPost = peer->amAnonymous(); - const auto silentPost = ShouldSendSilent(peer, file->to.options); FillMessagePostFlags(action, peer, flags); if (file->to.options.scheduled) { flags |= MessageFlag::IsOrWasScheduled; From 7779d021b4d4e04e80d954f1f19416951354135a Mon Sep 17 00:00:00 2001 From: Klemens Nanni <kn@openbsd.org> Date: Mon, 8 Jan 2024 22:49:46 +0100 Subject: [PATCH 08/73] update cmake/ submodule to include cppgir BSD fixes --- cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake b/cmake index 9620c4674..e541d6577 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 9620c467404f15a01bb5271af02b2676c2aaf306 +Subproject commit e541d6577d542c0e42788341c2ebf0b54e354461 From 26fa3db66d458f8ae113a8634526f432e2b177bd Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Tue, 9 Jan 2024 16:24:55 +0400 Subject: [PATCH 09/73] Replace deprecated medium display length with a number --- lib/xdg/org.telegram.desktop.metainfo.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/xdg/org.telegram.desktop.metainfo.xml b/lib/xdg/org.telegram.desktop.metainfo.xml index d787eada9..810a52b0b 100644 --- a/lib/xdg/org.telegram.desktop.metainfo.xml +++ b/lib/xdg/org.telegram.desktop.metainfo.xml @@ -45,12 +45,14 @@ <keyword>im</keyword> </keywords> <requires> - <display_length compare="ge">medium</display_length> + <!-- windowMinHeight from Telegram/SourceFiles/window/window.style --> + <display_length compare="ge">480</display_length> <internet>always</internet> + <!-- on-screen keyboards are too big for current minimal display height --> + <control>keyboard</control> </requires> <supports> <control>pointing</control> - <control>keyboard</control> <control>touch</control> </supports> <content_rating type="oars-1.1"> From 8138a26c2d761efa93069d8405649db1e85787a4 Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Tue, 9 Jan 2024 16:25:29 +0400 Subject: [PATCH 10/73] Add information about provided mime-type and D-Bus service --- lib/xdg/org.telegram.desktop.metainfo.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/xdg/org.telegram.desktop.metainfo.xml b/lib/xdg/org.telegram.desktop.metainfo.xml index 810a52b0b..874bbc2be 100644 --- a/lib/xdg/org.telegram.desktop.metainfo.xml +++ b/lib/xdg/org.telegram.desktop.metainfo.xml @@ -88,5 +88,7 @@ <launchable type="desktop-id">org.telegram.desktop.desktop</launchable> <provides> <binary>telegram-desktop</binary> + <dbus type="session">org.telegram.desktop</dbus> + <mediatype>x-scheme-handler/tg</mediatype> </provides> </component> From aa121aa1de79402c930e3ea2ad79508e35d64e6c Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Tue, 9 Jan 2024 23:22:46 +0400 Subject: [PATCH 11/73] Get rid of architecture whitelist from snapcraft.yaml So the Canonical builders build on new architectures as soon as they appear --- snap/snapcraft.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 16e8914b6..41dc00828 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -7,12 +7,6 @@ grade: stable confinement: strict compression: lzo -architectures: - - build-on: amd64 - - build-on: arm64 - - build-on: armhf - - build-on: ppc64el - apps: telegram-desktop: command: usr/bin/telegram-desktop From d803b3ae7d386f926742aad76856432056f0c624 Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Wed, 10 Jan 2024 07:01:22 +0400 Subject: [PATCH 12/73] Try to add mesa vulkan drivers to snap --- snap/snapcraft.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 41dc00828..4b28983d8 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -491,6 +491,7 @@ parts: - libxkbcommon0 - libxkbcommon-x11-0 - zlib1g + - mesa-vulkan-drivers override-pull: | QT=6.6.1 From 308fdcf9cf8d11042f778bfb478a4c298116ff74 Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Wed, 10 Jan 2024 09:59:34 +0400 Subject: [PATCH 13/73] Update submodules --- Telegram/build/docker/centos_env/Dockerfile | 2 +- Telegram/lib_ui | 2 +- Telegram/lib_webview | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Telegram/build/docker/centos_env/Dockerfile b/Telegram/build/docker/centos_env/Dockerfile index c9031a76d..ad9a28438 100644 --- a/Telegram/build/docker/centos_env/Dockerfile +++ b/Telegram/build/docker/centos_env/Dockerfile @@ -54,7 +54,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 4ff99fa2d8836f2cd9befe6cf38ce87dc20f276b \ + && git fetch --depth=1 origin a63f0887630c3e2130ee60ef322dd51ae3983c88 \ && git reset --hard FETCH_HEAD \ && rm -rf .git diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 30c5dfe6f..00f5bdacc 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 30c5dfe6f65babf234c889959061c97c4a2f391d +Subproject commit 00f5bdaccdff4f53e8ba347f09f2de161b7ca7da diff --git a/Telegram/lib_webview b/Telegram/lib_webview index 63e4ba48f..a1c84d636 160000 --- a/Telegram/lib_webview +++ b/Telegram/lib_webview @@ -1 +1 @@ -Subproject commit 63e4ba48fd8540fa3c2949d123160a2ce3411d70 +Subproject commit a1c84d636f7975781dece08939bbc24da8298c3c From 1e98e19aaf8f11449164b24e6b437f7798cb1a44 Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Wed, 10 Jan 2024 10:38:59 +0400 Subject: [PATCH 14/73] Add installed packages to cache key for macOS packaged action --- .github/workflows/mac_packaged.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/mac_packaged.yml b/.github/workflows/mac_packaged.yml index 631ff2a70..51ba9917a 100644 --- a/.github/workflows/mac_packaged.yml +++ b/.github/workflows/mac_packaged.yml @@ -73,6 +73,7 @@ jobs: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer xcodebuild -version > CACHE_KEY.txt + brew list --versions >> CACHE_KEY.txt echo $MANUAL_CACHING >> CACHE_KEY.txt echo "$GITHUB_WORKSPACE" >> CACHE_KEY.txt if [ "$AUTO_CACHING" = "1" ]; then From 333ef9b48ab0c3a009c0039775eb69ad189f62ad Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Fri, 12 Jan 2024 07:15:32 +0400 Subject: [PATCH 15/73] Hide connection widget when the window is not exposed --- .../view/history_view_top_bar_widget.cpp | 14 ++++++++++- .../window/window_connecting_widget.cpp | 23 ++++++++++++++----- .../window/window_connecting_widget.h | 2 ++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index 774081836..bb3407afd 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -55,6 +55,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_send_action.h" #include "chat_helpers/emoji_interactions.h" #include "base/unixtime.h" +#include "base/event_filter.h" #include "support/support_helper.h" #include "apiwrap.h" #include "api/api_chat_participants.h" @@ -230,6 +231,16 @@ TopBarWidget::TopBarWidget( updateConnectingState(); }, lifetime()); + base::install_event_filter( + this, + window()->windowHandle(), + [=](not_null<QEvent*> e) { + if (e->type() == QEvent::Expose) { + updateConnectingState(); + } + return base::EventFilterResult::Continue; + }); + setCursor(style::cur_pointer); } @@ -241,7 +252,8 @@ Main::Session &TopBarWidget::session() const { void TopBarWidget::updateConnectingState() { const auto state = _controller->session().mtp().dcstate(); - if (state == MTP::ConnectedState) { + const auto exposed = window()->windowHandle()->isExposed(); + if (state == MTP::ConnectedState || !exposed) { if (_connecting) { _connecting = nullptr; update(); diff --git a/Telegram/SourceFiles/window/window_connecting_widget.cpp b/Telegram/SourceFiles/window/window_connecting_widget.cpp index 3d3a5d2a3..d045b153c 100644 --- a/Telegram/SourceFiles/window/window_connecting_widget.cpp +++ b/Telegram/SourceFiles/window/window_connecting_widget.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "window/window_connecting_widget.h" +#include "base/event_filter.h" #include "ui/widgets/buttons.h" #include "ui/effects/radial_animation.h" #include "ui/painter.h" @@ -207,6 +208,14 @@ ConnectionState::ConnectionState( rpl::producer<bool> shown) : _account(account) , _parent(parent) +, _exposeFilter(base::install_event_filter( + parent->window()->windowHandle(), + [=](not_null<QEvent*> e) { + if (e->type() == QEvent::Expose) { + refreshState(); + } + return base::EventFilterResult::Continue; + })) , _refreshTimer([=] { refreshState(); }) , _currentLayout(computeLayout(_state)) { rpl::combine( @@ -290,6 +299,7 @@ void ConnectionState::setBottomSkip(int skip) { void ConnectionState::refreshState() { using Checker = Core::UpdateChecker; const auto state = [&]() -> State { + const auto exposed = _parent->window()->windowHandle()->isExposed(); const auto under = _widget && _widget->isOver(); const auto ready = (Checker().state() == Checker::State::Ready); const auto state = _account->mtp().dcstate(); @@ -297,18 +307,18 @@ void ConnectionState::refreshState() { if (state == MTP::ConnectingState || state == MTP::DisconnectedState || (state < 0 && state > -600)) { - return { State::Type::Connecting, proxy, under, ready }; + return { State::Type::Connecting, proxy, exposed, under, ready }; } else if (state < 0 && state >= -kMinimalWaitingStateDuration && _state.type != State::Type::Waiting) { - return { State::Type::Connecting, proxy, under, ready }; + return { State::Type::Connecting, proxy, exposed, under, ready }; } else if (state < 0) { const auto wait = ((-state) / 1000) + 1; - return { State::Type::Waiting, proxy, under, ready, wait }; + return { State::Type::Waiting, proxy, exposed, under, ready, wait }; } - return { State::Type::Connected, proxy, under, ready }; + return { State::Type::Connected, proxy, exposed, under, ready }; }(); - if (state.waitTillRetry > 0) { + if (state.exposed && state.waitTillRetry > 0) { _refreshTimer.callOnce(kRefreshTimeout); } if (state == _state) { @@ -421,7 +431,8 @@ auto ConnectionState::computeLayout(const State &state) const -> Layout { auto result = Layout(); result.proxyEnabled = state.useProxy; result.progressShown = (state.type != State::Type::Connected); - result.visible = !state.updateReady + result.visible = state.exposed + && !state.updateReady && (state.useProxy || state.type == State::Type::Connecting || state.type == State::Type::Waiting); diff --git a/Telegram/SourceFiles/window/window_connecting_widget.h b/Telegram/SourceFiles/window/window_connecting_widget.h index 5c391a9a6..7813ce5ad 100644 --- a/Telegram/SourceFiles/window/window_connecting_widget.h +++ b/Telegram/SourceFiles/window/window_connecting_widget.h @@ -46,6 +46,7 @@ private: }; Type type = Type::Connected; bool useProxy = false; + bool exposed = false; bool underCursor = false; bool updateReady = false; int waitTillRetry = 0; @@ -79,6 +80,7 @@ private: const not_null<Main::Account*> _account; not_null<Ui::RpWidget*> _parent; + base::unique_qptr<QObject> _exposeFilter; rpl::variable<int> _bottomSkip; base::unique_qptr<Widget> _widget; bool _forceHidden = false; From eca8c28dea1c59dc6ea5f48bd83fb3f06c4b2b8d Mon Sep 17 00:00:00 2001 From: Ilya Fedin <fedin-ilja2010@ya.ru> Date: Sat, 13 Jan 2024 00:50:29 +0400 Subject: [PATCH 16/73] Add missing QWindow includes --- .../SourceFiles/history/view/history_view_top_bar_widget.cpp | 2 ++ Telegram/SourceFiles/window/window_connecting_widget.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index bb3407afd..891f45927 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -65,6 +65,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_info.h" #include "styles/style_menu_icons.h" +#include <QtGui/QWindow> + namespace HistoryView { namespace { diff --git a/Telegram/SourceFiles/window/window_connecting_widget.cpp b/Telegram/SourceFiles/window/window_connecting_widget.cpp index d045b153c..7a757df68 100644 --- a/Telegram/SourceFiles/window/window_connecting_widget.cpp +++ b/Telegram/SourceFiles/window/window_connecting_widget.cpp @@ -23,6 +23,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "styles/style_window.h" +#include <QtGui/QWindow> + namespace Window { namespace { From dd1cca1a0ae880939242762de06e3d53d82440cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 19:58:13 +0000 Subject: [PATCH 17/73] Bump jinja2 from 3.1.2 to 3.1.3 in /Telegram/build/docker/centos_env Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.2 to 3.1.3. - [Release notes](https://github.com/pallets/jinja/releases) - [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/jinja/compare/3.1.2...3.1.3) --- updated-dependencies: - dependency-name: jinja2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> --- Telegram/build/docker/centos_env/poetry.lock | 28 +++++++++---------- .../build/docker/centos_env/pyproject.toml | 2 +- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Telegram/build/docker/centos_env/poetry.lock b/Telegram/build/docker/centos_env/poetry.lock index 3b86e84d5..08526811d 100644 --- a/Telegram/build/docker/centos_env/poetry.lock +++ b/Telegram/build/docker/centos_env/poetry.lock @@ -1,10 +1,15 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.3" description = "A very fast and expressive template engine." -category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, +] [package.dependencies] MarkupSafe = ">=2.0" @@ -16,21 +21,9 @@ i18n = ["Babel (>=2.7)"] name = "markupsafe" version = "2.1.1" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = false python-versions = ">=3.7" - -[metadata] -lock-version = "1.1" -python-versions = "^3.7" -content-hash = "fdf86553de6f950425c8ca77fe37127c9242c83445ce44b951ee4032ef72ea2f" - -[metadata.files] -jinja2 = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, -] -markupsafe = [ +files = [ {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, @@ -72,3 +65,8 @@ markupsafe = [ {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] + +[metadata] +lock-version = "2.0" +python-versions = "^3.7" +content-hash = "bac9a23a86839c72127e75f2cf181e331f59d96f723403d529e7ea19774ff9c4" diff --git a/Telegram/build/docker/centos_env/pyproject.toml b/Telegram/build/docker/centos_env/pyproject.toml index b6507ba3f..bba5c212f 100644 --- a/Telegram/build/docker/centos_env/pyproject.toml +++ b/Telegram/build/docker/centos_env/pyproject.toml @@ -6,7 +6,7 @@ authors = [] [tool.poetry.dependencies] python = "^3.7" -Jinja2 = "^3.1.2" +Jinja2 = "^3.1.3" [tool.poetry.dev-dependencies] From 0faf801de7853ff7a3270e6e4bf3ce23c255d6b7 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Wed, 3 Jan 2024 14:46:34 +0400 Subject: [PATCH 18/73] Update API scheme to layer 171. --- Telegram/SourceFiles/api/api_messages_search.cpp | 1 + .../SourceFiles/calls/calls_box_controller.cpp | 1 + .../SourceFiles/data/data_search_controller.cpp | 1 + Telegram/SourceFiles/dialogs/dialogs_widget.cpp | 3 +++ Telegram/SourceFiles/export/export_api_wrap.cpp | 1 + Telegram/SourceFiles/mtproto/scheme/api.tl | 15 ++++++++++++--- 6 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/api/api_messages_search.cpp b/Telegram/SourceFiles/api/api_messages_search.cpp index 15119b906..cc97e22c0 100644 --- a/Telegram/SourceFiles/api/api_messages_search.cpp +++ b/Telegram/SourceFiles/api/api_messages_search.cpp @@ -91,6 +91,7 @@ void MessagesSearch::searchRequest() { ? _from->input : MTP_inputPeerEmpty()), MTPInputPeer(), // saved_peer_id + MTPVector<MTPReaction>(), // saved_reaction MTPint(), // top_msg_id MTP_inputMessagesFilterEmpty(), MTP_int(0), // min_date diff --git a/Telegram/SourceFiles/calls/calls_box_controller.cpp b/Telegram/SourceFiles/calls/calls_box_controller.cpp index 9eb53580f..11c6347d5 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.cpp +++ b/Telegram/SourceFiles/calls/calls_box_controller.cpp @@ -521,6 +521,7 @@ void BoxController::loadMoreRows() { MTP_string(), // q MTP_inputPeerEmpty(), MTPInputPeer(), // saved_peer_id + MTPVector<MTPReaction>(), // saved_reaction MTPint(), // top_msg_id MTP_inputMessagesFilterPhoneCalls(MTP_flags(0)), MTP_int(0), // min_date diff --git a/Telegram/SourceFiles/data/data_search_controller.cpp b/Telegram/SourceFiles/data/data_search_controller.cpp index 688ce4ae9..43c5efb66 100644 --- a/Telegram/SourceFiles/data/data_search_controller.cpp +++ b/Telegram/SourceFiles/data/data_search_controller.cpp @@ -98,6 +98,7 @@ std::optional<SearchRequest> PrepareSearchRequest( MTP_string(query), MTP_inputPeerEmpty(), MTPInputPeer(), // saved_peer_id + MTPVector<MTPReaction>(), // saved_reaction MTP_int(topicRootId), filter, MTP_int(0), // min_date diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 4aa36ec38..f6ace227a 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1764,6 +1764,7 @@ bool Widget::searchMessages(bool searchCache) { ? _searchQueryFrom->input : MTP_inputPeerEmpty()), MTPInputPeer(), // saved_peer_id + MTPVector<MTPReaction>(), // saved_reaction MTP_int(topic ? topic->rootId() : 0), MTP_inputMessagesFilterEmpty(), MTP_int(0), // min_date @@ -2006,6 +2007,7 @@ void Widget::searchMore() { ? _searchQueryFrom->input : MTP_inputPeerEmpty()), MTPInputPeer(), // saved_peer_id + MTPVector<MTPReaction>(), // saved_reaction MTP_int(topic ? topic->rootId() : 0), MTP_inputMessagesFilterEmpty(), MTP_int(0), // min_date @@ -2079,6 +2081,7 @@ void Widget::searchMore() { ? _searchQueryFrom->input : MTP_inputPeerEmpty()), MTPInputPeer(), // saved_peer_id + MTPVector<MTPReaction>(), // saved_reaction MTPint(), // top_msg_id MTP_inputMessagesFilterEmpty(), MTP_int(0), // min_date diff --git a/Telegram/SourceFiles/export/export_api_wrap.cpp b/Telegram/SourceFiles/export/export_api_wrap.cpp index 61f29b16c..25fe29a71 100644 --- a/Telegram/SourceFiles/export/export_api_wrap.cpp +++ b/Telegram/SourceFiles/export/export_api_wrap.cpp @@ -1625,6 +1625,7 @@ void ApiWrap::requestChatMessages( MTP_string(), // query MTP_inputPeerSelf(), MTPInputPeer(), // saved_peer_id + MTPVector<MTPReaction>(), // saved_reaction MTPint(), // top_msg_id MTP_inputMessagesFilterEmpty(), MTP_int(0), // min_date diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index 87ce36bbc..fee427f9f 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -400,6 +400,7 @@ updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_r updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector<ReactionCount> qts:int = Update; updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector<DialogPeer> = Update; +updateSavedReactionTags#39c67432 = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -1366,7 +1367,7 @@ auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; -messageReactions#4f2b9479 flags:# min:flags.0?true can_see_list:flags.2?true results:Vector<ReactionCount> recent_reactions:flags.1?Vector<MessagePeerReaction> = MessageReactions; +messageReactions#4f2b9479 flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector<ReactionCount> recent_reactions:flags.1?Vector<MessagePeerReaction> = MessageReactions; messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector<MessagePeerReaction> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.MessageReactionsList; @@ -1643,6 +1644,11 @@ messages.savedDialogs#f83ae221 dialogs:Vector<SavedDialog> messages:Vector<Messa messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector<SavedDialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SavedDialogs; messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; +savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; + +messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; +messages.savedReactionTags#3259950a tags:Vector<SavedReactionTag> hash:long = messages.SavedReactionTags; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1802,7 +1808,7 @@ contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector<Inpu messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages; messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.search#a7b4e929 flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; +messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector<Reaction> top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages; @@ -1993,6 +1999,9 @@ messages.deleteSavedHistory#6e98102b flags:# peer:InputPeer max_id:int min_date: messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector<InputDialogPeer> = Bool; +messages.getSavedReactionTags#761ddacf hash:long = messages.SavedReactionTags; +messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; +messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; updates.getState#edd4882a = updates.State; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; @@ -2235,4 +2244,4 @@ premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector<int> peer:InputPeer = p premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; -// LAYER 170 +// LAYER 171 From 9b43d204e2c8fe2e471edb73ba5a9986eb4bd174 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Wed, 3 Jan 2024 14:46:50 +0400 Subject: [PATCH 19/73] Track and render reactions as tags in Saved Messages. --- .../SourceFiles/data/data_saved_messages.cpp | 4 +- Telegram/SourceFiles/data/data_types.h | 2 + Telegram/SourceFiles/history/history_item.cpp | 57 +++--- Telegram/SourceFiles/history/history_item.h | 1 + .../history/view/history_view_message.cpp | 6 +- .../view/reactions/history_view_reactions.cpp | 166 ++++++++++++++++-- .../view/reactions/history_view_reactions.h | 11 ++ Telegram/SourceFiles/ui/chat/chat.style | 6 + Telegram/SourceFiles/ui/empty_userpic.cpp | 2 +- 9 files changed, 216 insertions(+), 39 deletions(-) diff --git a/Telegram/SourceFiles/data/data_saved_messages.cpp b/Telegram/SourceFiles/data/data_saved_messages.cpp index 66bc87609..d81f97fe5 100644 --- a/Telegram/SourceFiles/data/data_saved_messages.cpp +++ b/Telegram/SourceFiles/data/data_saved_messages.cpp @@ -20,6 +20,8 @@ namespace { constexpr auto kPerPage = 50; constexpr auto kFirstPerPage = 10; +constexpr auto kListPerPage = 100; +constexpr auto kListFirstPerPage = 20; } // namespace @@ -82,7 +84,7 @@ void SavedMessages::sendLoadMore() { MTP_int(_offsetDate), MTP_int(_offsetId), _offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(), - MTP_int(kPerPage), + MTP_int(_offsetId ? kListPerPage : kListFirstPerPage), MTP_long(0)) // hash ).done([=](const MTPmessages_SavedDialogs &result) { apply(result, false); diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index 31c976859..46f75419a 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -313,6 +313,8 @@ enum class MessageFlag : uint64 { ShowSimilarChannels = (1ULL << 41), Sponsored = (1ULL << 42), + + ReactionsAreTags = (1ULL << 43), }; inline constexpr bool is_flag_type(MessageFlag) { return true; } using MessageFlags = base::flags<MessageFlag>; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index dcdd8b3d0..35a2dc7db 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -2429,6 +2429,10 @@ const std::vector<Data::MessageReaction> &HistoryItem::reactions() const { return _reactions ? _reactions->list() : kEmpty; } +bool HistoryItem::reactionsAreTags() const { + return _flags & MessageFlag::ReactionsAreTags; +} + auto HistoryItem::recentReactions() const -> const base::flat_map< Data::ReactionId, @@ -3556,31 +3560,40 @@ bool HistoryItem::changeReactions(const MTPMessageReactions *reactions) { } if (!reactions) { _flags &= ~MessageFlag::CanViewReactions; + if (_history->peer->isSelf()) { + _flags |= MessageFlag::ReactionsAreTags; + } return (base::take(_reactions) != nullptr); } - return reactions->match([&](const MTPDmessageReactions &data) { - if (data.is_can_see_list()) { - _flags |= MessageFlag::CanViewReactions; - } else { - _flags &= ~MessageFlag::CanViewReactions; + const auto &data = reactions->data(); + const auto empty = data.vresults().v.isEmpty(); + if (data.is_reactions_as_tags() + || (empty && _history->peer->isSelf())) { + _flags |= MessageFlag::ReactionsAreTags; + } else { + _flags &= ~MessageFlag::ReactionsAreTags; + } + if (data.is_can_see_list()) { + _flags |= MessageFlag::CanViewReactions; + } else { + _flags &= ~MessageFlag::CanViewReactions; + } + if (empty) { + return (base::take(_reactions) != nullptr); + } else if (!_reactions) { + _reactions = std::make_unique<Data::MessageReactions>(this); + } + const auto min = data.is_min(); + const auto &list = data.vresults().v; + const auto &recent = data.vrecent_reactions().value_or_empty(); + if (min && hasUnreadReaction()) { + // We can't update reactions from min if we have unread. + if (_reactions->checkIfChanged(list, recent, min)) { + updateReactionsUnknown(); } - if (data.vresults().v.isEmpty()) { - return (base::take(_reactions) != nullptr); - } else if (!_reactions) { - _reactions = std::make_unique<Data::MessageReactions>(this); - } - const auto min = data.is_min(); - const auto &list = data.vresults().v; - const auto &recent = data.vrecent_reactions().value_or_empty(); - if (min && hasUnreadReaction()) { - // We can't update reactions from min if we have unread. - if (_reactions->checkIfChanged(list, recent, min)) { - updateReactionsUnknown(); - } - return false; - } - return _reactions->change(list, recent, min); - }); + return false; + } + return _reactions->change(list, recent, min); } void HistoryItem::applyTTL(const MTPDmessage &data) { diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 412b9e057..75705eab8 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -454,6 +454,7 @@ public: not_null<UserData*> from) const; [[nodiscard]] crl::time lastReactionsRefreshTime() const; + [[nodiscard]] bool reactionsAreTags() const; [[nodiscard]] bool hasDirectLink() const; [[nodiscard]] bool changesWallPaper() const; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 4edffbe37..f319dfc9a 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -2917,8 +2917,12 @@ bool Message::isSignedAuthorElided() const { bool Message::embedReactionsInBottomInfo() const { const auto item = data(); const auto user = item->history()->peer->asUser(); - if (!user || user->isPremium() || user->session().premium()) { + if (!user + || user->isPremium() + || user->isSelf() + || user->session().premium()) { // Only in messages of a non premium user with a non premium user. + // In saved messages we use reactions for tags, we don't embed them. return false; } auto seenMy = false; diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp index 911472560..a7e83c029 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp @@ -55,6 +55,7 @@ struct InlineList::Button { int count = 0; int countTextWidth = 0; bool chosen = false; + bool tag = false; }; InlineList::InlineList( @@ -118,6 +119,7 @@ void InlineList::layoutButtons() { ) | ranges::views::transform([](const MessageReaction &reaction) { return not_null{ &reaction }; }) | ranges::to_vector; + const auto tags = _data.flags & Data::Flag::Tags; const auto &list = _owner->list(::Data::Reactions::Type::All); ranges::sort(sorted, [&]( not_null<const MessageReaction*> a, @@ -142,8 +144,10 @@ void InlineList::layoutButtons() { buttons.push_back((i != end(_buttons)) ? std::move(*i) : prepareButtonWithId(id)); - const auto j = _data.recent.find(id); - if (j != end(_data.recent) && !j->second.empty()) { + if (tags) { + setButtonTag(buttons.back()); + } else if (const auto j = _data.recent.find(id) + ; j != end(_data.recent) && !j->second.empty()) { setButtonUserpics(buttons.back(), j->second); } else { setButtonCount(buttons.back(), reaction->count); @@ -168,12 +172,22 @@ InlineList::Button InlineList::prepareButtonWithId(const ReactionId &id) { return result; } +void InlineList::setButtonTag(Button &button) { + if (button.tag) { + return; + } + button.userpics = nullptr; + button.count = 0; + button.tag = true; +} + void InlineList::setButtonCount(Button &button, int count) { - if (button.count == count && !button.userpics) { + if (!button.tag && button.count == count && !button.userpics) { return; } button.userpics = nullptr; button.count = count; + button.tag = false; button.countText = Lang::FormatCountToShort(count).string; button.countTextWidth = st::semiboldFont->width(button.countText); } @@ -181,6 +195,7 @@ void InlineList::setButtonCount(Button &button, int count) { void InlineList::setButtonUserpics( Button &button, const std::vector<not_null<PeerData*>> &peers) { + button.tag = false; if (!button.userpics) { button.userpics = std::make_unique<Userpics>(); } @@ -228,6 +243,10 @@ QSize InlineList::countOptimalSize() { const auto between = st::reactionInlineBetween; const auto padding = st::reactionInlinePadding; const auto size = st::reactionInlineSize; + const auto widthBaseTag = padding.left() + + size + + st::reactionInlineTagSkip + + padding.right(); const auto widthBaseCount = padding.left() + size + st::reactionInlineSkip @@ -245,7 +264,9 @@ QSize InlineList::countOptimalSize() { }; const auto height = padding.top() + size + padding.bottom(); for (auto &button : _buttons) { - const auto width = button.userpics + const auto width = button.tag + ? widthBaseTag + : button.userpics ? (widthBaseUserpics + userpicsWidth(button)) : (widthBaseCount + button.countTextWidth); button.geometry.setSize({ width, height }); @@ -336,7 +357,8 @@ void InlineList::paint( const auto padding = st::reactionInlinePadding; const auto size = st::reactionInlineSize; const auto skip = (size - st::reactionInlineImage) / 2; - const auto inbubble = (_data.flags & InlineListData::Flag::InBubble); + const auto tags = (_data.flags & Data::Flag::Tags); + const auto inbubble = (_data.flags & Data::Flag::InBubble); const auto flipped = (_data.flags & Data::Flag::Flipped); p.setFont(st::semiboldFont); for (const auto &button : _buttons) { @@ -366,21 +388,26 @@ void InlineList::paint( if (bubbleProgress > 0.) { auto hq = PainterHighQualityEnabler(p); p.setPen(Qt::NoPen); + auto opacity = 1.; + auto color = QColor(); if (inbubble) { if (!chosen) { - p.setOpacity(bubbleProgress * (context.outbg + opacity = bubbleProgress * (context.outbg ? kOutNonChosenOpacity - : kInNonChosenOpacity)); + : kInNonChosenOpacity); } else if (!bubbleReady) { - p.setOpacity(bubbleProgress); + opacity = bubbleProgress; } - p.setBrush(stm->msgFileBg); + color = stm->msgFileBg->c; } else { if (!bubbleReady) { - p.setOpacity(bubbleProgress); + opacity = bubbleProgress; } - p.setBrush(chosen ? st->msgServiceFg() : st->msgServiceBg()); + color = (chosen + ? st->msgServiceFg() + : st->msgServiceBg())->c; } + const auto radius = geometry.height() / 2.; const auto fill = geometry.marginsAdded({ flipped ? bubbleSkip : 0, @@ -388,7 +415,7 @@ void InlineList::paint( flipped ? 0 : bubbleSkip, 0, }); - p.drawRoundedRect(fill, radius, radius); + paintSingleBg(p, fill, color, opacity); if (inbubble && !chosen) { p.setOpacity(bubbleProgress); } @@ -434,7 +461,8 @@ void InlineList::paint( .target = image, }); } - if (bubbleProgress == 0.) { + if (tags || bubbleProgress == 0.) { + p.setOpacity(1.); continue; } resolveUserpicsImage(button); @@ -479,6 +507,115 @@ void InlineList::paint( } } +void InlineList::validateTagBg(const QColor &color) const { + if (!_tagBg.isNull() && _tagBgColor == color) { + return; + } + _tagBgColor = color; + + const auto padding = st::reactionInlinePadding; + const auto size = st::reactionInlineSize; + const auto width = padding.left() + + size + + st::reactionInlineTagSkip + + padding.right(); + const auto height = padding.top() + size + padding.bottom(); + const auto ratio = style::DevicePixelRatio(); + + auto mask = QImage( + QSize(width, height) * ratio, + QImage::Format_ARGB32_Premultiplied); + mask.setDevicePixelRatio(ratio); + + mask.fill(Qt::transparent); + auto p = QPainter(&mask); + + auto path = QPainterPath(); + const auto arrow = st::reactionInlineTagArrow; + const auto rradius = st::reactionInlineTagRightRadius * 1.; + const auto radius = st::reactionInlineTagLeftRadius - rradius; + const auto fg = QColor(255, 255, 255); + auto pen = QPen(fg); + pen.setWidthF(rradius * 2.); + pen.setJoinStyle(Qt::RoundJoin); + const auto rect = QRectF(0, 0, width, height).marginsRemoved( + { rradius, rradius, rradius, rradius }); + + const auto right = rect.x() + rect.width(); + const auto bottom = rect.y() + rect.height(); + path.moveTo(rect.x() + radius, rect.y()); + path.lineTo(right - arrow, rect.y()); + path.lineTo(right, rect.y() + rect.height() / 2); + path.lineTo(right - arrow, bottom); + path.lineTo(rect.x() + radius, bottom); + path.arcTo(QRectF(rect.x(), bottom - radius * 2, radius * 2, radius * 2), 270, -90); + path.lineTo(rect.x(), rect.y() + radius); + path.arcTo(QRectF(rect.x(), rect.y(), radius * 2, radius * 2), 180, -90); + path.closeSubpath(); + + const auto dsize = st::reactionInlineTagDot; + const auto dot = QRectF( + right - st::reactionInlineTagDotSkip - dsize, + rect.y() + (rect.height() - dsize) / 2., + dsize, + dsize); + + auto hq = PainterHighQualityEnabler(p); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.setPen(pen); + p.setBrush(fg); + p.drawPath(path); + + p.setPen(Qt::NoPen); + p.setBrush(QColor(255, 255, 255, 255 * 0.6)); + p.drawEllipse(dot); + + p.end(); + + _tagBg = style::colorizeImage(mask, color); +} + +void InlineList::paintSingleBg( + Painter &p, + const QRect &fill, + const QColor &color, + float64 opacity) const { + p.setOpacity(opacity); + if (!(_data.flags & Data::Flag::Tags)) { + const auto radius = fill.height() / 2.; + p.setBrush(color); + p.drawRoundedRect(fill, radius, radius); + return; + } + validateTagBg(color); + const auto ratio = style::DevicePixelRatio(); + const auto left = st::reactionInlineTagLeftRadius; + const auto right = (_tagBg.width() / ratio) - left; + Assert(right > 0); + const auto useLeft = std::min(fill.width(), left); + p.drawImage( + QRect(fill.x(), fill.y(), useLeft, fill.height()), + _tagBg, + QRect(0, 0, useLeft * ratio, _tagBg.height())); + const auto middle = fill.width() - left - right; + if (middle > 0) { + p.fillRect(fill.x() + left, fill.y(), middle, fill.height(), color); + } + if (const auto useRight = fill.width() - left; useRight > 0) { + p.drawImage( + QRect( + fill.x() + fill.width() - useRight, + fill.y(), + useRight, + fill.height()), + _tagBg, + QRect(_tagBg.width() - useRight * ratio, + 0, + useRight * ratio, + _tagBg.height())); + } +} + bool InlineList::getState( QPoint point, not_null<TextState*> outResult) const { @@ -654,7 +791,8 @@ InlineListData InlineListDataFromMessage(not_null<Message*> message) { } } result.flags = (message->hasOutLayout() ? Flag::OutLayout : Flag()) - | (message->embedReactionsInBubble() ? Flag::InBubble : Flag()); + | (message->embedReactionsInBubble() ? Flag::InBubble : Flag()) + | (item->reactionsAreTags() ? Flag::Tags : Flag()); return result; } diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h index 398ec0cd8..cc4fa80d8 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h @@ -41,6 +41,7 @@ struct InlineListData { InBubble = 0x01, OutLayout = 0x02, Flipped = 0x04, + Tags = 0x08, }; friend inline constexpr bool is_flag_type(Flag) { return true; }; using Flags = base::flags<Flag>; @@ -103,6 +104,7 @@ private: void layout(); void layoutButtons(); + void setButtonTag(Button &button); void setButtonCount(Button &button, int count); void setButtonUserpics( Button &button, @@ -115,6 +117,13 @@ private: QPoint innerTopLeft, const PaintContext &context, const QColor &textColor) const; + void paintSingleBg( + Painter &p, + const QRect &fill, + const QColor &color, + float64 opacity) const; + + void validateTagBg(const QColor &color) const; QSize countOptimalSize() override; @@ -124,6 +133,8 @@ private: Data _data; std::vector<Button> _buttons; QSize _skipBlock; + mutable QImage _tagBg; + mutable QColor _tagBgColor; mutable QImage _customCache; mutable int _customSkip = 0; bool _hasCustomEmoji = false; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 7507e0e6b..bc54f7366 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -851,6 +851,12 @@ reactionInlinePadding: margins(5px, 2px, 7px, 2px); reactionInlineSize: 18px; reactionInlineImage: 32px; reactionInlineSkip: 3px; +reactionInlineTagSkip: 6px; +reactionInlineTagLeftRadius: 6px; +reactionInlineTagRightRadius: 3px; +reactionInlineTagArrow: 5px; +reactionInlineTagDot: 5px; +reactionInlineTagDotSkip: 2px; reactionInlineBetween: 4px; reactionInlineInBubbleLeft: -3px; reactionInlineUserpicsPadding: margins(1px, 1px, 1px, 1px); diff --git a/Telegram/SourceFiles/ui/empty_userpic.cpp b/Telegram/SourceFiles/ui/empty_userpic.cpp index d2b11df2c..1eebf7a11 100644 --- a/Telegram/SourceFiles/ui/empty_userpic.cpp +++ b/Telegram/SourceFiles/ui/empty_userpic.cpp @@ -440,7 +440,7 @@ void EmptyUserpic::PaintHiddenAuthor( { 0., st::premiumButtonBg2->c }, { 1., st::premiumButtonBg3->c }, }); - const auto &fg = st::historyPeerUserpicFg; + const auto &fg = st::premiumButtonFg; PaintHiddenAuthor(p, x, y, outerWidth, size, QBrush(bg), fg); } From 9aacff8b540843cb6765013c59f16c103e0f51c6 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Thu, 4 Jan 2024 11:47:59 +0400 Subject: [PATCH 20/73] Request correct saved/default reaction tags. --- Telegram/SourceFiles/api/api_updates.cpp | 4 + .../data/data_message_reactions.cpp | 177 +++++++++++++++++- .../SourceFiles/data/data_message_reactions.h | 36 ++++ .../history_view_reactions_button.cpp | 4 +- .../SourceFiles/window/section_widget.cpp | 20 +- 5 files changed, 227 insertions(+), 14 deletions(-) diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index c9714d67e..dde1a68cd 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -2508,6 +2508,10 @@ void Updates::feedUpdate(const MTPUpdate &update) { session().data().reactions().refreshRecentDelayed(); } break; + case mtpc_updateSavedReactionTags: { + session().data().reactions().refreshMyTagsDelayed(); + } break; + ////// Cloud saved GIFs case mtpc_updateSavedGifs: { session().data().stickers().setLastSavedGifsUpdate(0); diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index 9dc677fbf..b6eadde69 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -38,6 +38,7 @@ constexpr auto kPollEach = 20 * crl::time(1000); constexpr auto kSizeForDownscale = 64; constexpr auto kRecentRequestTimeout = 10 * crl::time(1000); constexpr auto kRecentReactionsLimit = 40; +constexpr auto kMyTagsRequestTimeout = crl::time(1000); constexpr auto kTopRequestDelay = 60 * crl::time(1000); constexpr auto kTopReactionsLimit = 14; @@ -64,6 +65,27 @@ constexpr auto kTopReactionsLimit = 14; return result; } +[[nodiscard]] std::vector<MyTagInfo> ListFromMTP( + const MTPDmessages_savedReactionTags &data) { + const auto &list = data.vtags().v; + auto result = std::vector<MyTagInfo>(); + result.reserve(list.size()); + for (const auto &reaction : list) { + const auto &data = reaction.data(); + const auto id = ReactionFromMTP(data.vreaction()); + if (id.empty()) { + LOG(("API Error: reactionEmpty in messages.reactions.")); + } else { + result.push_back({ + .id = id, + .title = qs(data.vtitle().value_or_empty()), + .count = data.vcount().v, + }); + } + } + return result; +} + [[nodiscard]] Reaction CustomReaction(not_null<DocumentData*> document) { return Reaction{ .id = { { document->id } }, @@ -121,6 +143,8 @@ PossibleItemReactionsRef LookupPossibleReactions( const auto &full = reactions->list(Reactions::Type::Active); const auto &top = reactions->list(Reactions::Type::Top); const auto &recent = reactions->list(Reactions::Type::Recent); + const auto &myTags = reactions->list(Reactions::Type::MyTags); + const auto &tags = reactions->list(Reactions::Type::Tags); const auto &all = item->reactions(); const auto limit = UniqueReactionsLimit(peer); const auto premiumPossible = session->premiumPossible(); @@ -143,7 +167,19 @@ PossibleItemReactionsRef LookupPossibleReactions( } }; reactions->clearTemporary(); - if (limited) { + if (item->reactionsAreTags()) { + auto &&all = ranges::views::concat(myTags, tags); + result.recent.reserve(myTags.size() + tags.size()); + for (const auto &reaction : all) { + if (premiumPossible + || ranges::contains(tags, reaction.id, &Reaction::id)) { + if (added.emplace(reaction.id).second) { + result.recent.push_back(&reaction); + } + } + } + result.customAllowed = premiumPossible; + } else if (limited) { result.recent.reserve(all.size()); add([&](const Reaction &reaction) { return ranges::contains(all, reaction.id, &MessageReaction::id); @@ -193,12 +229,14 @@ PossibleItemReactionsRef LookupPossibleReactions( result.customAllowed = (allowed.type == AllowedReactionsType::All) && premiumPossible; } - const auto i = ranges::find( - result.recent, - reactions->favoriteId(), - &Reaction::id); - if (i != end(result.recent) && i != begin(result.recent)) { - std::rotate(begin(result.recent), i, i + 1); + if (!item->reactionsAreTags()) { + const auto i = ranges::find( + result.recent, + reactions->favoriteId(), + &Reaction::id); + if (i != end(result.recent) && i != begin(result.recent)) { + std::rotate(begin(result.recent), i, i + 1); + } } return result; } @@ -280,16 +318,42 @@ void Reactions::refreshDefault() { requestDefault(); } +void Reactions::refreshMyTags() { + requestMyTags(); +} + +void Reactions::refreshMyTagsDelayed() { + if (_myTagsRequestId || _myTagsRequestScheduled) { + return; + } + _myTagsRequestScheduled = true; + base::call_delayed(kMyTagsRequestTimeout, &_owner->session(), [=] { + if (_myTagsRequestScheduled) { + requestMyTags(); + } + }); +} + +void Reactions::refreshTags() { + requestTags(); +} + const std::vector<Reaction> &Reactions::list(Type type) const { switch (type) { case Type::Active: return _active; case Type::Recent: return _recent; case Type::Top: return _top; case Type::All: return _available; + case Type::MyTags: return _myTags; + case Type::Tags: return _tags; } Unexpected("Type in Reactions::list."); } +const std::vector<MyTagInfo> &Reactions::myTagsInfo() const { + return _myTagsInfo; +} + ReactionId Reactions::favoriteId() const { return _favoriteId; } @@ -375,6 +439,14 @@ rpl::producer<> Reactions::favoriteUpdates() const { return _favoriteUpdated.events(); } +rpl::producer<> Reactions::myTagsUpdates() const { + return _myTagsUpdated.events(); +} + +rpl::producer<> Reactions::tagsUpdates() const { + return _tagsUpdated.events(); +} + void Reactions::preloadImageFor(const ReactionId &id) { if (_images.contains(id) || id.emoji().isEmpty()) { return; @@ -617,6 +689,46 @@ void Reactions::requestGeneric() { }).send(); } +void Reactions::requestMyTags() { + if (_myTagsRequestId) { + return; + } + auto &api = _owner->session().api(); + _myTagsRequestScheduled = false; + _myTagsRequestId = api.request(MTPmessages_GetSavedReactionTags( + MTP_long(_myTagsHash) + )).done([=](const MTPmessages_SavedReactionTags &result) { + _myTagsRequestId = 0; + result.match([&](const MTPDmessages_savedReactionTags &data) { + updateMyTags(data); + }, [](const MTPDmessages_savedReactionTagsNotModified&) { + }); + }).fail([=] { + _myTagsRequestId = 0; + _myTagsHash = 0; + }).send(); +} + +void Reactions::requestTags() { + if (_tagsRequestId) { + return; + } + auto &api = _owner->session().api(); + _tagsRequestId = api.request(MTPmessages_GetDefaultTagReactions( + MTP_long(_tagsHash) + )).done([=](const MTPmessages_Reactions &result) { + _tagsRequestId = 0; + result.match([&](const MTPDmessages_reactions &data) { + updateTags(data); + }, [](const MTPDmessages_reactionsNotModified&) { + }); + }).fail([=] { + _tagsRequestId = 0; + _tagsHash = 0; + }).send(); + +} + void Reactions::updateTop(const MTPDmessages_reactions &data) { _topHash = data.vhash().v; _topIds = ListFromMTP(data); @@ -685,6 +797,23 @@ void Reactions::updateGeneric(const MTPDmessages_stickerSet &data) { } } +void Reactions::updateMyTags(const MTPDmessages_savedReactionTags &data) { + _myTagsHash = data.vhash().v; + _myTagsInfo = ListFromMTP(data); + _myTagsIds = _myTagsInfo | ranges::views::transform( + &MyTagInfo::id + ) | ranges::to_vector; + _myTags = resolveByIds(_myTagsIds, _unresolvedMyTags); + _myTagsUpdated.fire({}); +} + +void Reactions::updateTags(const MTPDmessages_reactions &data) { + _tagsHash = data.vhash().v; + _tagsIds = ListFromMTP(data); + _tags = resolveByIds(_tagsIds, _unresolvedTags); + _tagsUpdated.fire({}); +} + void Reactions::recentUpdated() { _topRefreshTimer.callOnce(kTopRequestDelay); _recentUpdated.fire({}); @@ -696,9 +825,25 @@ void Reactions::defaultUpdated() { if (_genericAnimations.empty()) { requestGeneric(); } + refreshMyTags(); + refreshTags(); _defaultUpdated.fire({}); } +void Reactions::myTagsUpdated() { + if (_genericAnimations.empty()) { + requestGeneric(); + } + _myTagsUpdated.fire({}); +} + +void Reactions::tagsUpdated() { + if (_genericAnimations.empty()) { + requestGeneric(); + } + _tagsUpdated.fire({}); +} + not_null<CustomEmojiManager::Listener*> Reactions::resolveListener() { return static_cast<CustomEmojiManager::Listener*>(this); } @@ -710,6 +855,10 @@ void Reactions::customEmojiResolveDone(not_null<DocumentData*> document) { const auto top = (i != end(_unresolvedTop)); const auto j = _unresolvedRecent.find(id); const auto recent = (j != end(_unresolvedRecent)); + const auto k = _unresolvedMyTags.find(id); + const auto myTag = (k != end(_unresolvedMyTags)); + const auto l = _unresolvedTags.find(id); + const auto tag = (l != end(_unresolvedTags)); if (favorite) { _unresolvedFavoriteId = ReactionId(); _favorite = resolveById(_favoriteId); @@ -722,6 +871,14 @@ void Reactions::customEmojiResolveDone(not_null<DocumentData*> document) { _unresolvedRecent.erase(j); _recent = resolveByIds(_recentIds, _unresolvedRecent); } + if (myTag) { + _unresolvedMyTags.erase(k); + _myTags = resolveByIds(_myTagsIds, _unresolvedMyTags); + } + if (tag) { + _unresolvedTags.erase(l); + _tags = resolveByIds(_tagsIds, _unresolvedTags); + } if (favorite) { _favoriteUpdated.fire({}); } @@ -731,6 +888,12 @@ void Reactions::customEmojiResolveDone(not_null<DocumentData*> document) { if (recent) { _recentUpdated.fire({}); } + if (myTag) { + _myTagsUpdated.fire({}); + } + if (tag) { + _tagsUpdated.fire({}); + } } std::optional<Reaction> Reactions::resolveById(const ReactionId &id) { diff --git a/Telegram/SourceFiles/data/data_message_reactions.h b/Telegram/SourceFiles/data/data_message_reactions.h index 61b29107d..e43538a11 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.h +++ b/Telegram/SourceFiles/data/data_message_reactions.h @@ -56,6 +56,12 @@ struct PossibleItemReactions { [[nodiscard]] PossibleItemReactionsRef LookupPossibleReactions( not_null<HistoryItem*> item); +struct MyTagInfo { + ReactionId id; + QString title; + int count = 0; +}; + class Reactions final : private CustomEmojiManager::Listener { public: explicit Reactions(not_null<Session*> owner); @@ -70,14 +76,20 @@ public: void refreshRecent(); void refreshRecentDelayed(); void refreshDefault(); + void refreshMyTags(); + void refreshMyTagsDelayed(); + void refreshTags(); enum class Type { Active, Recent, Top, All, + MyTags, + Tags, }; [[nodiscard]] const std::vector<Reaction> &list(Type type) const; + [[nodiscard]] const std::vector<MyTagInfo> &myTagsInfo() const; [[nodiscard]] ReactionId favoriteId() const; [[nodiscard]] const Reaction *favorite() const; void setFavorite(const ReactionId &id); @@ -88,6 +100,8 @@ public: [[nodiscard]] rpl::producer<> recentUpdates() const; [[nodiscard]] rpl::producer<> defaultUpdates() const; [[nodiscard]] rpl::producer<> favoriteUpdates() const; + [[nodiscard]] rpl::producer<> myTagsUpdates() const; + [[nodiscard]] rpl::producer<> tagsUpdates() const; enum class ImageSize { BottomInfo, @@ -130,14 +144,20 @@ private: void requestRecent(); void requestDefault(); void requestGeneric(); + void requestMyTags(); + void requestTags(); void updateTop(const MTPDmessages_reactions &data); void updateRecent(const MTPDmessages_reactions &data); void updateDefault(const MTPDmessages_availableReactions &data); void updateGeneric(const MTPDmessages_stickerSet &data); + void updateMyTags(const MTPDmessages_savedReactionTags &data); + void updateTags(const MTPDmessages_reactions &data); void recentUpdated(); void defaultUpdated(); + void myTagsUpdated(); + void tagsUpdated(); [[nodiscard]] std::optional<Reaction> resolveById(const ReactionId &id); [[nodiscard]] std::vector<Reaction> resolveByIds( @@ -167,6 +187,13 @@ private: std::vector<Reaction> _recent; std::vector<ReactionId> _recentIds; base::flat_set<ReactionId> _unresolvedRecent; + std::vector<Reaction> _myTags; + std::vector<ReactionId> _myTagsIds; + std::vector<MyTagInfo> _myTagsInfo; + base::flat_set<ReactionId> _unresolvedMyTags; + std::vector<Reaction> _tags; + std::vector<ReactionId> _tagsIds; + base::flat_set<ReactionId> _unresolvedTags; std::vector<Reaction> _top; std::vector<ReactionId> _topIds; base::flat_set<ReactionId> _unresolvedTop; @@ -184,6 +211,8 @@ private: rpl::event_stream<> _recentUpdated; rpl::event_stream<> _defaultUpdated; rpl::event_stream<> _favoriteUpdated; + rpl::event_stream<> _myTagsUpdated; + rpl::event_stream<> _tagsUpdated; // We need &i->second stay valid while inserting new items. // So we use std::map instead of base::flat_map here. @@ -203,6 +232,13 @@ private: mtpRequestId _genericRequestId = 0; + mtpRequestId _myTagsRequestId = 0; + bool _myTagsRequestScheduled = false; + uint64 _myTagsHash = 0; + + mtpRequestId _tagsRequestId = 0; + uint64 _tagsHash = 0; + base::flat_map<ReactionId, ImageSet> _images; rpl::lifetime _imagesLoadLifetime; bool _waitingForList = false; diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp index 91ad93484..2081a85e7 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp @@ -895,7 +895,9 @@ void SetupManagerList( reactions.topUpdates(), reactions.recentUpdates(), reactions.defaultUpdates(), - reactions.favoriteUpdates() + reactions.favoriteUpdates(), + reactions.myTagsUpdates(), + reactions.tagsUpdates() ) | rpl::start_with_next([=] { if (!state->timer.isActive()) { state->timer.callOnce(kRefreshListDelay); diff --git a/Telegram/SourceFiles/window/section_widget.cpp b/Telegram/SourceFiles/window/section_widget.cpp index 47e1196ea..8da39b10e 100644 --- a/Telegram/SourceFiles/window/section_widget.cpp +++ b/Telegram/SourceFiles/window/section_widget.cpp @@ -529,14 +529,22 @@ bool ShowReactPremiumError( || ranges::contains(item->chosenReactions(), id) || item->history()->peer->isBroadcast()) { return false; - } - const auto &list = controller->session().data().reactions().list( - Data::Reactions::Type::Active); - const auto i = ranges::find(list, id, &Data::Reaction::id); - if (i == end(list) || !i->premium) { - if (!id.custom()) { + } else if (item->reactionsAreTags()) { + const auto &list = controller->session().data().reactions().list( + Data::Reactions::Type::Tags); + const auto i = ranges::find(list, id, &Data::Reaction::id); + if (i != end(list)) { return false; } + } else { + const auto &list = controller->session().data().reactions().list( + Data::Reactions::Type::Active); + const auto i = ranges::find(list, id, &Data::Reaction::id); + if (i == end(list) || !i->premium) { + if (!id.custom()) { + return false; + } + } } ShowPremiumPreviewBox(controller, PremiumPreview::InfiniteReactions); return true; From e667436a98cb9c766a3b24cf23d53af7c96095f0 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Thu, 4 Jan 2024 12:08:49 +0400 Subject: [PATCH 21/73] Track my tags usages. --- .../data/data_message_reactions.cpp | 57 +++++++++++++++++++ .../SourceFiles/data/data_message_reactions.h | 4 ++ 2 files changed, 61 insertions(+) diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index b6eadde69..9e1726b7a 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -378,6 +378,56 @@ void Reactions::setFavorite(const ReactionId &id) { applyFavorite(id); } +void Reactions::incrementMyTag(const ReactionId &id) { + auto i = ranges::find(_myTagsInfo, id, &MyTagInfo::id); + if (i == end(_myTagsInfo)) { + _myTagsInfo.push_back({ .id = id, .count = 0 }); + i = end(_myTagsInfo) - 1; + } + ++i->count; + while (i != begin(_myTagsInfo)) { + auto j = i - 1; + if (j->count >= i->count) { + break; + } + std::swap(*i, *j); + i = j; + } + scheduleMyTagsUpdate(); +} + +void Reactions::decrementMyTag(const ReactionId &id) { + auto i = ranges::find(_myTagsInfo, id, &MyTagInfo::id); + if (i->count <= 0) { + return; + } + --i->count; + while (i + 1 != end(_myTagsInfo)) { + auto j = i + 1; + if (j->count <= i->count) { + break; + } + std::swap(*i, *j); + i = j; + } + scheduleMyTagsUpdate(); +} + +void Reactions::scheduleMyTagsUpdate() { + _myTagsUpdateScheduled = true; + crl::on_main(&session(), [=] { + if (!_myTagsUpdateScheduled) { + return; + } + _myTagsUpdateScheduled = false; + _myTagsIds = _myTagsInfo | ranges::views::transform( + &MyTagInfo::id + ) | ranges::to_vector; + _myTags = resolveByIds(_myTagsIds, _unresolvedMyTags); + _myTagsUpdated.fire({}); + }); +} + DocumentData *Reactions::chooseGenericAnimation( not_null<DocumentData*> custom) const { const auto sticker = custom->sticker(); @@ -1155,6 +1205,10 @@ void MessageReactions::add(const ReactionId &id, bool addToRecent) { return; } auto my = 0; + const auto tags = _item->reactionsAreTags(); + if (tags) { + history->owner().reactions().incrementMyTag(id); + } _list.erase(ranges::remove_if(_list, [&](MessageReaction &one) { const auto removing = one.my && (my == myLimit || ++my == myLimit); if (!removing) { @@ -1176,6 +1230,9 @@ void MessageReactions::add(const ReactionId &id, bool addToRecent) { } } } + if (tags) { + history->owner().reactions().decrementMyTag(one.id); + } return removed; }), end(_list)); const auto peer = history->peer; diff --git a/Telegram/SourceFiles/data/data_message_reactions.h b/Telegram/SourceFiles/data/data_message_reactions.h index e43538a11..2743bffc8 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.h +++ b/Telegram/SourceFiles/data/data_message_reactions.h @@ -93,6 +93,8 @@ public: [[nodiscard]] ReactionId favoriteId() const; [[nodiscard]] const Reaction *favorite() const; void setFavorite(const ReactionId &id); + void incrementMyTag(const ReactionId &id); + void decrementMyTag(const ReactionId &id); [[nodiscard]] DocumentData *chooseGenericAnimation( not_null<DocumentData*> custom) const; @@ -165,6 +167,7 @@ private: base::flat_set<ReactionId> &unresolved); void resolve(const ReactionId &id); void applyFavorite(const ReactionId &id); + void scheduleMyTagsUpdate(); [[nodiscard]] std::optional<Reaction> parse( const MTPAvailableReaction &entry); @@ -234,6 +237,7 @@ private: mtpRequestId _myTagsRequestId = 0; bool _myTagsRequestScheduled = false; + bool _myTagsUpdateScheduled = false; uint64 _myTagsHash = 0; mtpRequestId _tagsRequestId = 0; From 9c151ca151b20a7400e13c48064f853c111cd243 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Fri, 5 Jan 2024 11:25:45 +0400 Subject: [PATCH 22/73] Allow filtering Saved Messages search by tags. --- Telegram/CMakeLists.txt | 2 + Telegram/SourceFiles/dialogs/dialogs.style | 3 + .../dialogs/dialogs_inner_widget.cpp | 115 +++++++- .../dialogs/dialogs_inner_widget.h | 8 + .../dialogs/dialogs_search_tags.cpp | 246 ++++++++++++++++++ .../SourceFiles/dialogs/dialogs_search_tags.h | 78 ++++++ .../SourceFiles/dialogs/dialogs_widget.cpp | 49 +++- Telegram/SourceFiles/dialogs/dialogs_widget.h | 4 + .../view/reactions/history_view_reactions.cpp | 46 ++-- .../view/reactions/history_view_reactions.h | 3 + 10 files changed, 518 insertions(+), 36 deletions(-) create mode 100644 Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp create mode 100644 Telegram/SourceFiles/dialogs/dialogs_search_tags.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 4f9db7939..59c701340 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -609,6 +609,8 @@ PRIVATE dialogs/dialogs_row.h dialogs/dialogs_search_from_controllers.cpp dialogs/dialogs_search_from_controllers.h + dialogs/dialogs_search_tags.cpp + dialogs/dialogs_search_tags.h dialogs/dialogs_widget.cpp dialogs/dialogs_widget.h dialogs/ui/dialogs_layout.cpp diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 055675b2d..c45ea636f 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -623,3 +623,6 @@ dialogsStoriesTooltipHide: IconButton(defaultIconButton) { searchedBarHeight: 32px; searchedBarFont: normalFont; searchedBarPosition: point(17px, 7px); + +dialogsSearchTagSkip: point(8px, 4px); +dialogsSearchTagBottom: 10px; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index afbf0ca77..a9f1d1b41 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_indexed_list.h" #include "dialogs/dialogs_widget.h" #include "dialogs/dialogs_search_from_controllers.h" +#include "dialogs/dialogs_search_tags.h" #include "history/history.h" #include "history/history_item.h" #include "core/shortcuts.h" @@ -40,6 +41,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat_filters.h" #include "data/data_cloud_file.h" #include "data/data_changes.h" +#include "data/data_message_reactions.h" #include "data/data_saved_messages.h" #include "data/data_stories.h" #include "data/stickers/data_stickers.h" @@ -477,18 +479,26 @@ int InnerWidget::peerSearchOffset() const { + st::searchedBarHeight; } -int InnerWidget::searchedOffset() const { - auto result = peerSearchOffset(); +int InnerWidget::searchInChatOffset() const { + auto result = peerSearchOffset() - st::searchedBarHeight; if (!_peerSearchResults.empty()) { result += (_peerSearchResults.size() * st::dialogsRowHeight) + st::searchedBarHeight; } - result += searchInChatSkip(); return result; } +int InnerWidget::searchedOffset() const { + return searchInChatOffset() + + searchInChatSkip() + + st::searchedBarHeight; +} + int InnerWidget::searchInChatSkip() const { auto result = 0; + if (_searchTags) { + result += _searchTags->height(); + } if (_searchInChat) { result += st::searchedBarHeight + st::dialogsSearchInHeight; } @@ -1111,12 +1121,20 @@ void InnerWidget::paintSearchInChat( auto height = searchInChatSkip(); auto top = 0; + if (_searchTags) { + const auto height = _searchTags->height(); + p.fillRect(0, top, width(), height, currentBg()); + const auto position = QPoint(_searchTagsLeft, 0); + _searchTags->paint(p, position, context.now, context.paused); + top += height; + } p.setFont(st::searchedBarFont); if (_searchInChat) { - top += st::searchedBarHeight; - p.fillRect(0, 0, width(), top, st::searchedBarBg); + const auto bar = st::searchedBarHeight; + p.fillRect(0, top, width(), top + bar, st::searchedBarBg); p.setPen(st::searchedBarFg); - p.drawTextLeft(st::searchedBarPosition.x(), st::searchedBarPosition.y(), width(), tr::lng_dlg_search_in(tr::now)); + p.drawTextLeft(st::searchedBarPosition.x(), top + st::searchedBarPosition.y(), width(), tr::lng_dlg_search_in(tr::now)); + top += bar; } auto fullRect = QRect(0, top, width(), height - top); p.fillRect(fullRect, currentBg()); @@ -1276,6 +1294,21 @@ void InnerWidget::selectByMouse(QPoint globalPosition) { _lastMousePosition = globalPosition; _lastRowLocalMouseX = local.x(); + const auto tagBase = QPoint(_searchTagsLeft, searchInChatOffset()); + const auto tagPoint = local - tagBase; + const auto inTags = _searchTags + && QRect( + tagBase, + QSize(width() - 2 * _searchTagsLeft, _searchTags->height()) + ).contains(local); + const auto tagLink = inTags + ? _searchTags->lookupHandler(tagPoint) + : nullptr; + ClickHandler::setActive(tagLink); + if (inTags) { + setCursor(tagLink ? style::cur_pointer : style::cur_default); + } + const auto w = width(); const auto mouseY = local.y(); clearIrrelevantState(); @@ -1370,7 +1403,7 @@ void InnerWidget::selectByMouse(QPoint globalPosition) { updateSelectedRow(); } } - if (wasSelected != isSelected()) { + if (!inTags && wasSelected != isSelected()) { setCursor(wasSelected ? style::cur_default : style::cur_pointer); } } @@ -1452,6 +1485,7 @@ void InnerWidget::mousePressEvent(QMouseEvent *e) { QSize(width(), _st->height), row->repaint()); } + ClickHandler::pressed(); if (anim::Disabled() && (!_pressed || !_pressed->entry()->isPinnedDialog(_filterId))) { mousePressReleased(e->globalPos(), e->button(), e->modifiers()); @@ -1743,6 +1777,9 @@ void InnerWidget::mousePressReleased( chooseRow(modifiers, pressedTopicRootId); } } + if (auto activated = ClickHandler::unpressed()) { + ActivateClickHandler(window(), activated, { button }); + } } void InnerWidget::setCollapsedPressed(int pressed) { @@ -1825,9 +1862,10 @@ void InnerWidget::moveCancelSearchButtons() { st::columnMinimalWidthLeft - _narrowWidth); const auto left = widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchInChat->width(); const auto top = (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2; - _cancelSearchInChat->moveToLeft(left, st::searchedBarHeight + top); - const auto skip = _searchInChat ? (st::searchedBarHeight + st::dialogsSearchInHeight + st::lineWidth) : 0; - _cancelSearchFromUser->moveToLeft(left, skip + top); + const auto skip = st::searchedBarHeight + (_searchTags ? _searchTags->height() : 0); + _cancelSearchInChat->moveToLeft(left, skip + top); + const auto next = _searchInChat ? (skip + st::dialogsSearchInHeight + st::lineWidth) : 0; + _cancelSearchFromUser->moveToLeft(left, next + top); } void InnerWidget::dialogRowReplaced( @@ -2330,7 +2368,9 @@ void InnerWidget::applyFilterUpdate(QString newFilter, bool force) { newFilter = words.isEmpty() ? QString() : words.join(' '); if (newFilter != _filter || force) { _filter = newFilter; - if (_filter.isEmpty() && !_searchFromPeer) { + if (_filter.isEmpty() + && !_searchFromPeer + && _searchTagsSelected.empty()) { clearFilter(); } else { setState(WidgetState::Filtered); @@ -2350,7 +2390,9 @@ void InnerWidget::applyFilterUpdate(QString newFilter, bool force) { top += i->row->height(); } }; - if (!_searchInChat && !_searchFromPeer && !words.isEmpty()) { + if (!_searchInChat + && !_searchFromPeer + && !words.isEmpty()) { if (_savedSublists) { const auto owner = &session().data(); append(owner->savedMessages().chatsList()->indexed()); @@ -2791,6 +2833,11 @@ void InnerWidget::refresh(bool toTop) { return refreshWithCollapsedRows(toTop); } refreshEmptyLabel(); + if (_searchTags) { + _searchTagsLeft = st::dialogsFilterSkip + + st::dialogsFilterPadding.x(); + _searchTags->resizeToWidth(width() - 2 * _searchTagsLeft); + } auto h = 0; if (_state == WidgetState::Default) { if (_shownList->empty()) { @@ -2926,6 +2973,43 @@ void InnerWidget::searchInChat(Key key, PeerData *from) { } else if (const auto migrateFrom = peer->migrateFrom()) { _searchInMigrated = peer->owner().history(migrateFrom); } + + if (peer->isSelf()) { + const auto reactions = &peer->owner().reactions(); + const auto list = [=] { + return reactions->list(Data::Reactions::Type::MyTags); + }; + _searchTags = std::make_unique<SearchTags>( + &peer->owner(), + rpl::single( + list() + ) | rpl::then( + reactions->myTagsUpdates() | rpl::map(list) + )); + + _searchTags->selectedValue( + ) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) { + _searchTagsSelected = std::move(list); + }, _searchTags->lifetime()); + + _searchTags->repaintRequests() | rpl::start_with_next([=] { + const auto height = _searchTags->height(); + update(0, searchInChatOffset(), width(), height); + }, _searchTags->lifetime()); + + _searchTags->heightValue() | rpl::filter( + rpl::mappers::_1 > 0 + ) | rpl::start_with_next([=] { + refresh(); + moveCancelSearchButtons(); + }, _searchTags->lifetime()); + } else { + _searchTags = nullptr; + _searchTagsSelected.clear(); + } + } else { + _searchTags = nullptr; + _searchTagsSelected.clear(); } _searchInChat = key; _searchFromPeer = from; @@ -2957,6 +3041,13 @@ void InnerWidget::searchInChat(Key key, PeerData *from) { _searchInChat || !_filter.isEmpty()); } +auto InnerWidget::searchTagsValue() const +-> rpl::producer<std::vector<Data::ReactionId>> { + return _searchTags + ? _searchTags->selectedValue() + : rpl::single(std::vector<Data::ReactionId>()); +} + void InnerWidget::refreshSearchInChatLabel() { const auto dialog = [&] { if (const auto topic = _searchInChat.topic()) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 7915bd912..d511c65e8 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -43,6 +43,7 @@ namespace Data { class Thread; class Folder; class Forum; +struct ReactionId; } // namespace Data namespace Dialogs::Ui { @@ -57,6 +58,7 @@ namespace Dialogs { class Row; class FakeRow; class IndexedList; +class SearchTags; struct ChosenRow { Key key; @@ -138,6 +140,8 @@ public: [[nodiscard]] bool hasFilteredResults() const; void searchInChat(Key key, PeerData *from); + [[nodiscard]] auto searchTagsValue() const + -> rpl::producer<std::vector<Data::ReactionId>>; void applyFilterUpdate(QString newFilter, bool force = false); void onHashtagFilterUpdate(QStringView newFilter); @@ -325,6 +329,7 @@ private: [[nodiscard]] int filteredIndex(int y) const; [[nodiscard]] int filteredHeight(int till = -1) const; [[nodiscard]] int peerSearchOffset() const; + [[nodiscard]] int searchInChatOffset() const; [[nodiscard]] int searchedOffset() const; [[nodiscard]] int searchInChatSkip() const; @@ -482,6 +487,9 @@ private: mutable Ui::PeerUserpicView _searchFromUserUserpic; Ui::Text::String _searchInChatText; Ui::Text::String _searchFromUserText; + std::unique_ptr<SearchTags> _searchTags; + std::vector<Data::ReactionId> _searchTagsSelected; + int _searchTagsLeft = 0; RowDescriptor _menuRow; base::flat_map< diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp b/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp new file mode 100644 index 000000000..22a15ec55 --- /dev/null +++ b/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp @@ -0,0 +1,246 @@ +/* +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 "dialogs/dialogs_search_tags.h" + +#include "data/stickers/data_custom_emoji.h" +#include "data/data_document.h" +#include "data/data_message_reactions.h" +#include "data/data_session.h" +#include "history/view/reactions/history_view_reactions.h" +#include "ui/effects/animation_value.h" +#include "ui/power_saving.h" +#include "styles/style_chat.h" +#include "styles/style_dialogs.h" + +namespace Dialogs { + +struct SearchTags::Tag { + Data::ReactionId id; + std::unique_ptr<Ui::Text::CustomEmoji> custom; + mutable QImage image; + QRect geometry; + ClickHandlerPtr link; + bool selected = false; +}; + +SearchTags::SearchTags( + not_null<Data::Session*> owner, + rpl::producer<std::vector<Data::Reaction>> tags) +: _owner(owner) { + std::move( + tags + ) | rpl::start_with_next([=](const std::vector<Data::Reaction> &list) { + fill(list); + }, _lifetime); + + style::PaletteChanged( + ) | rpl::start_with_next([=] { + _normalBg = _selectedBg = QImage(); + }, _lifetime); +} + +SearchTags::~SearchTags() = default; + +void SearchTags::fill(const std::vector<Data::Reaction> &list) { + const auto selected = collectSelected(); + _tags.clear(); + _tags.reserve(list.size()); + const auto link = [&](Data::ReactionId id) { + return std::make_shared<LambdaClickHandler>(crl::guard(this, [=] { + const auto i = ranges::find(_tags, id, &Tag::id); + if (i != end(_tags)) { + i->selected = !i->selected; + _selectedChanges.fire({}); + } + })); + }; + for (const auto &reaction : list) { + const auto id = reaction.id; + const auto customId = id.custom(); + _tags.push_back({ + .id = id, + .custom = (customId + ? _owner->customEmojiManager().create( + customId, + [=] { _repaintRequests.fire({}); }) + : nullptr), + .link = link(id), + .selected = ranges::contains(selected, id), + }); + if (!customId) { + _owner->reactions().preloadImageFor(id); + } + } + if (_width > 0) { + layout(); + } +} + +void SearchTags::layout() { + Expects(_width > 0); + + const auto &bg = validateBg(false); + const auto skip = st::dialogsSearchTagSkip; + const auto size = bg.size() / bg.devicePixelRatio(); + const auto xsingle = size.width() + skip.x(); + const auto ysingle = size.height() + skip.y(); + const auto columns = std::max((_width + skip.x()) / xsingle, 1); + const auto rows = (_tags.size() + columns - 1) / columns; + for (auto row = 0; row != rows; ++row) { + for (auto column = 0; column != columns; ++column) { + const auto index = row * columns + column; + if (index >= _tags.size()) { + break; + } + const auto x = column * xsingle; + const auto y = row * ysingle; + _tags[index].geometry = QRect(QPoint(x, y), size); + } + } + const auto bottom = st::dialogsSearchTagBottom; + _height = rows ? (rows * ysingle - skip.y() + bottom) : 0; +} + +void SearchTags::resizeToWidth(int width) { + if (_width == width || width <= 0) { + return; + } + _width = width; + layout(); +} + +int SearchTags::height() const { + return _height.current(); +} + +rpl::producer<int> SearchTags::heightValue() const { + return _height.value(); +} + +rpl::producer<> SearchTags::repaintRequests() const { + return _repaintRequests.events(); +} + +ClickHandlerPtr SearchTags::lookupHandler(QPoint point) const { + for (const auto &tag : _tags) { + if (tag.geometry.contains(point.x(), point.y())) { + return tag.link; + } + } + return nullptr; +} + +auto SearchTags::selectedValue() const +-> rpl::producer<std::vector<Data::ReactionId>> { + return _selectedChanges.events() | rpl::map([=] { + return collectSelected(); + }); +} + +void SearchTags::paintCustomFrame( + QPainter &p, + not_null<Ui::Text::CustomEmoji*> emoji, + QPoint innerTopLeft, + crl::time now, + bool paused, + const QColor &textColor) const { + if (_customCache.isNull()) { + using namespace Ui::Text; + const auto size = st::emojiSize; + const auto factor = style::DevicePixelRatio(); + const auto adjusted = AdjustCustomEmojiSize(size); + _customCache = QImage( + QSize(adjusted, adjusted) * factor, + QImage::Format_ARGB32_Premultiplied); + _customCache.setDevicePixelRatio(factor); + _customSkip = (size - adjusted) / 2; + } + _customCache.fill(Qt::transparent); + auto q = QPainter(&_customCache); + emoji->paint(q, { + .textColor = textColor, + .now = now, + .paused = paused || On(PowerSaving::kEmojiChat), + }); + q.end(); + _customCache = Images::Round( + std::move(_customCache), + (Images::Option::RoundLarge + | Images::Option::RoundSkipTopRight + | Images::Option::RoundSkipBottomRight)); + + p.drawImage( + innerTopLeft + QPoint(_customSkip, _customSkip), + _customCache); +} + +void SearchTags::paint( + QPainter &p, + QPoint position, + crl::time now, + bool paused) const { + const auto size = st::reactionInlineSize; + const auto skip = (size - st::reactionInlineImage) / 2; + const auto padding = st::reactionInlinePadding; + for (const auto &tag : _tags) { + const auto geometry = tag.geometry.translated(position); + p.drawImage(geometry.topLeft(), validateBg(tag.selected)); + if (!tag.custom && tag.image.isNull()) { + tag.image = _owner->reactions().resolveImageFor( + tag.id, + ::Data::Reactions::ImageSize::InlineList); + } + const auto inner = geometry.marginsRemoved(padding); + const auto image = QRect( + inner.topLeft() + QPoint(skip, skip), + QSize(st::reactionInlineImage, st::reactionInlineImage)); + if (const auto custom = tag.custom.get()) { + const auto textFg = tag.selected + ? st::dialogsNameFgActive->c + : st::dialogsNameFgOver->c; + paintCustomFrame( + p, + custom, + inner.topLeft(), + now, + paused, + textFg); + } else if (!tag.image.isNull()) { + p.drawImage(image.topLeft(), tag.image); + } + } +} + +const QImage &SearchTags::validateBg(bool selected) const { + using namespace HistoryView::Reactions; + auto &image = selected ? _selectedBg : _normalBg; + if (image.isNull()) { + const auto tagBg = selected + ? st::dialogsBgActive->c + : st::dialogsBgOver->c; + const auto dotBg = selected + ? anim::with_alpha(tagBg, InlineList::TagDotAlpha()) + : st::windowSubTextFg->c; + image = InlineList::PrepareTagBg(tagBg, dotBg); + } + return image; +} + +std::vector<Data::ReactionId> SearchTags::collectSelected() const { + return _tags | ranges::views::filter( + &Tag::selected + ) | ranges::views::transform( + &Tag::id + ) | ranges::to_vector; +} + +rpl::lifetime &SearchTags::lifetime() { + return _lifetime; +} + +} // namespace Dialogs diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_tags.h b/Telegram/SourceFiles/dialogs/dialogs_search_tags.h new file mode 100644 index 000000000..b1c193878 --- /dev/null +++ b/Telegram/SourceFiles/dialogs/dialogs_search_tags.h @@ -0,0 +1,78 @@ +/* +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 "base/weak_ptr.h" + +namespace Data { +class Session; +struct Reaction; +struct ReactionId; +} // namespace Data + +namespace Ui::Text { +class CustomEmoji; +} // namespace Ui::Text + +namespace Dialogs { + +class SearchTags final : public base::has_weak_ptr { +public: + SearchTags( + not_null<Data::Session*> owner, + rpl::producer<std::vector<Data::Reaction>> tags); + ~SearchTags(); + + void resizeToWidth(int width); + [[nodiscard]] int height() const; + [[nodiscard]] rpl::producer<int> heightValue() const; + [[nodiscard]] rpl::producer<> repaintRequests() const; + + [[nodiscard]] ClickHandlerPtr lookupHandler(QPoint point) const; + [[nodiscard]] auto selectedValue() const + -> rpl::producer<std::vector<Data::ReactionId>>; + + void paint( + QPainter &p, + QPoint position, + crl::time now, + bool paused) const; + + [[nodiscard]] rpl::lifetime &lifetime(); + +private: + struct Tag; + + void fill(const std::vector<Data::Reaction> &list); + void paintCustomFrame( + QPainter &p, + not_null<Ui::Text::CustomEmoji*> emoji, + QPoint innerTopLeft, + crl::time now, + bool paused, + const QColor &textColor) const; + void layout(); + [[nodiscard]] std::vector<Data::ReactionId> collectSelected() const; + [[nodiscard]] const QImage &validateBg(bool selected) const; + + const not_null<Data::Session*> _owner; + std::vector<Tag> _tags; + rpl::event_stream<> _selectedChanges; + rpl::event_stream<> _repaintRequests; + mutable QImage _normalBg; + mutable QImage _selectedBg; + mutable QImage _customCache; + mutable int _customSkip = 0; + rpl::variable<int> _height; + int _width = 0; + + rpl::lifetime _lifetime; + +}; + +} // namespace Dialogs diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index f6ace227a..2f19148fa 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1713,7 +1713,7 @@ void Widget::loadMoreBlockedByDate() { bool Widget::searchMessages(bool searchCache) { auto result = false; auto q = currentSearchQuery().trimmed(); - if (q.isEmpty() && !_searchFromAuthor) { + if (q.isEmpty() && !_searchFromAuthor && _searchTags.empty()) { cancelSearchRequest(); _api.request(base::take(_peerSearchRequest)).cancel(); _api.request(base::take(_topicSearchRequest)).cancel(); @@ -1730,6 +1730,7 @@ bool Widget::searchMessages(bool searchCache) { if (i != _searchCache.end()) { _searchQuery = q; _searchQueryFrom = _searchFromAuthor; + _searchQueryTags = _searchTags; _searchNextRate = 0; _searchFull = _searchFullMigrated = false; cancelSearchRequest(); @@ -1741,9 +1742,12 @@ bool Widget::searchMessages(bool searchCache) { 0); result = true; } - } else if (_searchQuery != q || _searchQueryFrom != _searchFromAuthor) { + } else if (_searchQuery != q + || _searchQueryFrom != _searchFromAuthor + || _searchQueryTags != _searchTags) { _searchQuery = q; _searchQueryFrom = _searchFromAuthor; + _searchQueryTags = _searchTags; _searchNextRate = 0; _searchFull = _searchFullMigrated = false; cancelSearchRequest(); @@ -1757,14 +1761,20 @@ bool Widget::searchMessages(bool searchCache) { using Flag = MTPmessages_Search::Flag; _searchRequest = session().api().request(MTPmessages_Search( MTP_flags((topic ? Flag::f_top_msg_id : Flag()) - | (_searchQueryFrom ? Flag::f_from_id : Flag())), + | (_searchQueryFrom ? Flag::f_from_id : Flag()) + | (_searchQueryTags.empty() + ? Flag() + : Flag::f_saved_reaction)), peer->input, MTP_string(_searchQuery), (_searchQueryFrom ? _searchQueryFrom->input : MTP_inputPeerEmpty()), MTPInputPeer(), // saved_peer_id - MTPVector<MTPReaction>(), // saved_reaction + MTP_vector_from_range( + _searchQueryTags | ranges::views::transform( + Data::ReactionToMTP + )), MTP_int(topic ? topic->rootId() : 0), MTP_inputMessagesFilterEmpty(), MTP_int(0), // min_date @@ -1868,6 +1878,7 @@ bool Widget::searchMessages(bool searchCache) { bool Widget::searchForPeersRequired(const QString &query) const { return !_searchInChat && !_searchFromAuthor + && _searchTags.empty() && !_openedForum && !query.isEmpty() && (query[0] != '#'); @@ -1876,6 +1887,7 @@ bool Widget::searchForPeersRequired(const QString &query) const { bool Widget::searchForTopicsRequired(const QString &query) const { return !_searchInChat && !_searchFromAuthor + && _searchTags.empty() && _openedForum && !query.isEmpty() && (query[0] != '#') @@ -2000,14 +2012,20 @@ void Widget::searchMore() { using Flag = MTPmessages_Search::Flag; _searchRequest = session().api().request(MTPmessages_Search( MTP_flags((topic ? Flag::f_top_msg_id : Flag()) - | (_searchQueryFrom ? Flag::f_from_id : Flag())), + | (_searchQueryFrom ? Flag::f_from_id : Flag()) + | (_searchQueryTags.empty() + ? Flag() + : Flag::f_saved_reaction)), peer->input, MTP_string(_searchQuery), (_searchQueryFrom ? _searchQueryFrom->input : MTP_inputPeerEmpty()), MTPInputPeer(), // saved_peer_id - MTPVector<MTPReaction>(), // saved_reaction + MTP_vector_from_range( + _searchQueryTags | ranges::views::transform( + Data::ReactionToMTP + )), MTP_int(topic ? topic->rootId() : 0), MTP_inputMessagesFilterEmpty(), MTP_int(0), // min_date @@ -2401,7 +2419,7 @@ void Widget::applyFilterUpdate(bool force) { updateStoriesVisibility(); const auto filterText = currentSearchQuery(); _inner->applyFilterUpdate(filterText, force); - if (filterText.isEmpty() && !_searchFromAuthor) { + if (filterText.isEmpty() && !_searchFromAuthor && _searchTags.empty()) { clearSearchCache(); } _cancelSearch->toggle(!filterText.isEmpty(), anim::type::normal); @@ -2417,7 +2435,9 @@ void Widget::applyFilterUpdate(bool force) { _peerSearchQuery = QString(); } - if (_chooseFromUser->toggled() || _searchFromAuthor) { + if (_chooseFromUser->toggled() + || _searchFromAuthor + || !_searchTags.empty()) { auto switchToChooseFrom = HistoryView::SwitchToChooseFromQuery(); if (_lastFilterText != switchToChooseFrom && switchToChooseFrom.startsWith(_lastFilterText) @@ -2619,6 +2639,18 @@ bool Widget::setSearchInChat(Key chat, PeerData *from) { controller()->closeFolder(); } _inner->searchInChat(_searchInChat, _searchFromAuthor); + _searchTagsLifetime = _inner->searchTagsValue( + ) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) { + if (_searchTags != list) { + clearSearchCache(); + _searchTags = std::move(list); + if (_searchTags.empty()) { + applyFilterUpdate(true); + } else { + searchMessages(); + } + } + }); if (_subsectionTopBar) { _subsectionTopBar->searchEnableJumpToDate( _openedForum && _searchInChat); @@ -2639,6 +2671,7 @@ void Widget::clearSearchCache() { } _searchQuery = QString(); _searchQueryFrom = nullptr; + _searchQueryTags.clear(); _topicSearchQuery = QString(); _topicSearchOffsetDate = 0; _topicSearchOffsetId = _topicSearchOffsetTopicId = 0; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 711509625..5ab53e2f9 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -22,6 +22,7 @@ class Error; namespace Data { class Forum; enum class StorySourcesList : uchar; +struct ReactionId; } // namespace Data namespace Main { @@ -285,6 +286,8 @@ private: Dialogs::Key _searchInChat; History *_searchInMigrated = nullptr; PeerData *_searchFromAuthor = nullptr; + std::vector<Data::ReactionId> _searchTags; + rpl::lifetime _searchTagsLifetime; QString _lastFilterText; rpl::event_stream<rpl::producer<Stories::Content>> _storiesContents; @@ -313,6 +316,7 @@ private: QString _searchQuery; PeerData *_searchQueryFrom = nullptr; + std::vector<Data::ReactionId> _searchQueryTags; int32 _searchNextRate = 0; bool _searchFull = false; bool _searchFullMigrated = false; diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp index a7e83c029..292774899 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp @@ -507,12 +507,11 @@ void InlineList::paint( } } -void InlineList::validateTagBg(const QColor &color) const { - if (!_tagBg.isNull() && _tagBgColor == color) { - return; - } - _tagBgColor = color; +float64 InlineList::TagDotAlpha() { + return 0.6; +} +QImage InlineList::PrepareTagBg(QColor tagBg, QColor dotBg) { const auto padding = st::reactionInlinePadding; const auto size = st::reactionInlineSize; const auto width = padding.left() @@ -522,20 +521,19 @@ void InlineList::validateTagBg(const QColor &color) const { const auto height = padding.top() + size + padding.bottom(); const auto ratio = style::DevicePixelRatio(); - auto mask = QImage( + auto result = QImage( QSize(width, height) * ratio, QImage::Format_ARGB32_Premultiplied); - mask.setDevicePixelRatio(ratio); + result.setDevicePixelRatio(ratio); - mask.fill(Qt::transparent); - auto p = QPainter(&mask); + result.fill(Qt::transparent); + auto p = QPainter(&result); auto path = QPainterPath(); const auto arrow = st::reactionInlineTagArrow; const auto rradius = st::reactionInlineTagRightRadius * 1.; const auto radius = st::reactionInlineTagLeftRadius - rradius; - const auto fg = QColor(255, 255, 255); - auto pen = QPen(fg); + auto pen = QPen(tagBg); pen.setWidthF(rradius * 2.); pen.setJoinStyle(Qt::RoundJoin); const auto rect = QRectF(0, 0, width, height).marginsRemoved( @@ -548,9 +546,15 @@ void InlineList::validateTagBg(const QColor &color) const { path.lineTo(right, rect.y() + rect.height() / 2); path.lineTo(right - arrow, bottom); path.lineTo(rect.x() + radius, bottom); - path.arcTo(QRectF(rect.x(), bottom - radius * 2, radius * 2, radius * 2), 270, -90); + path.arcTo( + QRectF(rect.x(), bottom - radius * 2, radius * 2, radius * 2), + 270, + -90); path.lineTo(rect.x(), rect.y() + radius); - path.arcTo(QRectF(rect.x(), rect.y(), radius * 2, radius * 2), 180, -90); + path.arcTo( + QRectF(rect.x(), rect.y(), radius * 2, radius * 2), + 180, + -90); path.closeSubpath(); const auto dsize = st::reactionInlineTagDot; @@ -563,16 +567,26 @@ void InlineList::validateTagBg(const QColor &color) const { auto hq = PainterHighQualityEnabler(p); p.setCompositionMode(QPainter::CompositionMode_Source); p.setPen(pen); - p.setBrush(fg); + p.setBrush(tagBg); p.drawPath(path); p.setPen(Qt::NoPen); - p.setBrush(QColor(255, 255, 255, 255 * 0.6)); + p.setBrush(dotBg); p.drawEllipse(dot); p.end(); - _tagBg = style::colorizeImage(mask, color); + return result; +} + +void InlineList::validateTagBg(const QColor &color) const { + if (!_tagBg.isNull() && _tagBgColor == color) { + return; + } + _tagBgColor = color; + auto dot = color; + dot.setAlphaF(dot.alphaF() * TagDotAlpha()); + _tagBg = PrepareTagBg(color, anim::with_alpha(color, TagDotAlpha())); } void InlineList::paintSingleBg( diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h index cc4fa80d8..619e1f053 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h @@ -93,6 +93,9 @@ public: ReactionId, std::unique_ptr<Ui::ReactionFlyAnimation>> animations); + [[nodiscard]] static float64 TagDotAlpha(); + [[nodiscard]] static QImage PrepareTagBg(QColor tagBg, QColor dotBg); + private: struct Userpics { QImage image; From f5fcfaba0c137a27518446bf0bfc79d0d6988c36 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Fri, 5 Jan 2024 16:34:49 +0400 Subject: [PATCH 23/73] Add search in saved sublist. --- .../dialogs/dialogs_inner_widget.cpp | 26 ++++++++----- .../dialogs/dialogs_inner_widget.h | 1 + .../SourceFiles/dialogs/dialogs_widget.cpp | 39 +++++++++++++------ .../view/history_view_sublist_section.cpp | 28 +++++++++++++ .../view/history_view_sublist_section.h | 2 + .../view/history_view_top_bar_widget.cpp | 4 +- 6 files changed, 79 insertions(+), 21 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index a9f1d1b41..d809c893e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -43,6 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_changes.h" #include "data/data_message_reactions.h" #include "data/data_saved_messages.h" +#include "data/data_saved_sublist.h" #include "data/data_stories.h" #include "data/stickers/data_stickers.h" #include "data/data_send_action.h" @@ -502,7 +503,7 @@ int InnerWidget::searchInChatSkip() const { if (_searchInChat) { result += st::searchedBarHeight + st::dialogsSearchInHeight; } - if (_searchFromPeer) { + if (_searchFromShown) { if (_searchInChat) { result += st::lineWidth; } @@ -1139,7 +1140,7 @@ void InnerWidget::paintSearchInChat( auto fullRect = QRect(0, top, width(), height - top); p.fillRect(fullRect, currentBg()); if (_searchInChat) { - if (_searchFromPeer) { + if (_searchFromShown) { p.fillRect(QRect(0, top + st::dialogsSearchInHeight, width(), st::lineWidth), st::shadowFg); } p.setPen(st::dialogsNameFg); @@ -1153,15 +1154,17 @@ void InnerWidget::paintSearchInChat( } else { paintSearchInPeer(p, peer, _searchInChatUserpic, top, _searchInChatText); } + } else if (const auto sublist = _searchInChat.sublist()) { + paintSearchInSaved(p, top, _searchInChatText); } else { Unexpected("Empty Key in paintSearchInChat."); } top += st::dialogsSearchInHeight + st::lineWidth; } - if (_searchFromPeer) { + if (_searchFromShown) { p.setPen(st::dialogsTextFg); p.setTextPalette(st::dialogsSearchFromPalette); - paintSearchInPeer(p, _searchFromPeer, _searchFromUserUserpic, top, _searchFromUserText); + paintSearchInPeer(p, _searchFromShown, _searchFromUserUserpic, top, _searchFromUserText); p.restoreTextPalette(); } } @@ -2967,7 +2970,9 @@ bool InnerWidget::hasFilteredResults() const { void InnerWidget::searchInChat(Key key, PeerData *from) { _searchInMigrated = nullptr; - if (const auto peer = key.peer()) { + const auto sublist = key.sublist(); + const auto peer = sublist ? session().user().get() : key.peer(); + if (peer) { if (const auto migrateTo = peer->migrateTo()) { return searchInChat(peer->owner().history(migrateTo), from); } else if (const auto migrateFrom = peer->migrateFrom()) { @@ -3013,15 +3018,16 @@ void InnerWidget::searchInChat(Key key, PeerData *from) { } _searchInChat = key; _searchFromPeer = from; + _searchFromShown = key.sublist() ? key.sublist()->peer().get() : from; if (_searchInChat) { onHashtagFilterUpdate(QStringView()); _cancelSearchInChat->show(); } else { _cancelSearchInChat->hide(); } - if (_searchFromPeer) { + if (_searchFromShown) { _cancelSearchFromUser->show(); - _searchFromUserUserpic = _searchFromPeer->createUserpicView(); + _searchFromUserUserpic = _searchFromShown->createUserpicView(); } else { _cancelSearchFromUser->hide(); _searchFromUserUserpic = {}; @@ -3030,7 +3036,7 @@ void InnerWidget::searchInChat(Key key, PeerData *from) { refreshSearchInChatLabel(); } - if (const auto peer = _searchInChat.peer()) { + if (peer) { _searchInChatUserpic = peer->createUserpicView(); } else { _searchInChatUserpic = {}; @@ -3059,6 +3065,8 @@ void InnerWidget::refreshSearchInChatLabel() { return tr::lng_replies_messages(tr::now); } return peer->name(); + } else if (_searchInChat.sublist()) { + return tr::lng_saved_messages(tr::now); } return QString(); }(); @@ -3068,7 +3076,7 @@ void InnerWidget::refreshSearchInChatLabel() { dialog, Ui::DialogTextOptions()); } - const auto from = _searchFromPeer ? _searchFromPeer->name() : QString(); + const auto from = _searchFromShown ? _searchFromShown->name() : u""_q; if (!from.isEmpty()) { const auto fromUserText = tr::lng_dlg_search_from( tr::now, diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index d511c65e8..f252b7add 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -483,6 +483,7 @@ private: Key _searchInChat; History *_searchInMigrated = nullptr; PeerData *_searchFromPeer = nullptr; + PeerData *_searchFromShown = nullptr; mutable Ui::PeerUserpicView _searchInChatUserpic; mutable Ui::PeerUserpicView _searchFromUserUserpic; Ui::Text::String _searchInChatText; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 2f19148fa..eeeb09c9f 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -67,6 +67,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_changes.h" #include "data/data_download_manager.h" #include "data/data_chat_filters.h" +#include "data/data_saved_sublist.h" #include "data/data_stories.h" #include "info/downloads/info_downloads_widget.h" #include "info/info_memento.h" @@ -1756,21 +1757,27 @@ bool Widget::searchMessages(bool searchCache) { auto &histories = session().data().histories(); const auto type = Data::Histories::RequestType::History; const auto history = session().data().history(peer); + const auto sublist = _openedForum + ? nullptr + : _searchInChat.sublist(); + const auto fromPeer = sublist ? nullptr : _searchQueryFrom; + const auto savedPeer = sublist + ? sublist->peer().get() + : nullptr; _searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn<void()> finish) { const auto type = SearchRequestType::PeerFromStart; using Flag = MTPmessages_Search::Flag; _searchRequest = session().api().request(MTPmessages_Search( MTP_flags((topic ? Flag::f_top_msg_id : Flag()) - | (_searchQueryFrom ? Flag::f_from_id : Flag()) + | (fromPeer ? Flag::f_from_id : Flag()) + | (savedPeer ? Flag::f_saved_peer_id : Flag()) | (_searchQueryTags.empty() ? Flag() : Flag::f_saved_reaction)), peer->input, MTP_string(_searchQuery), - (_searchQueryFrom - ? _searchQueryFrom->input - : MTP_inputPeerEmpty()), - MTPInputPeer(), // saved_peer_id + (fromPeer ? fromPeer->input : MTP_inputPeerEmpty()), + (savedPeer ? savedPeer->input : MTP_inputPeerEmpty()), MTP_vector_from_range( _searchQueryTags | ranges::views::transform( Data::ReactionToMTP @@ -1922,6 +1929,7 @@ void Widget::searchMessages(const QString &query, Key inChat) { const auto inChatChanged = [&] { const auto inPeer = inChat.peer(); const auto inTopic = inChat.topic(); + const auto inSublist = inChat.sublist(); if (!inTopic && _openedForum && inPeer == _openedForum->channel() @@ -1931,7 +1939,7 @@ void Widget::searchMessages(const QString &query, Key inChat) { } else if ((inTopic || (inPeer && !inPeer->isForum())) && (inChat == _searchInChat)) { return false; - } else if (const auto inPeer = inChat.peer()) { + } else if (inPeer) { if (const auto to = inPeer->migrateTo()) { if (to == _searchInChat.peer() && !_searchInChat.topic()) { return false; @@ -2005,6 +2013,13 @@ void Widget::searchMore() { const auto topic = searchInTopic(); const auto type = Data::Histories::RequestType::History; const auto history = session().data().history(peer); + const auto sublist = _openedForum + ? nullptr + : _searchInChat.sublist(); + const auto fromPeer = sublist ? nullptr : _searchQueryFrom; + const auto savedPeer = sublist + ? sublist->peer().get() + : nullptr; _searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn<void()> finish) { const auto type = _lastSearchId ? SearchRequestType::PeerFromOffset @@ -2012,16 +2027,15 @@ void Widget::searchMore() { using Flag = MTPmessages_Search::Flag; _searchRequest = session().api().request(MTPmessages_Search( MTP_flags((topic ? Flag::f_top_msg_id : Flag()) - | (_searchQueryFrom ? Flag::f_from_id : Flag()) + | (fromPeer ? Flag::f_from_id : Flag()) + | (savedPeer ? Flag::f_saved_peer_id : Flag()) | (_searchQueryTags.empty() ? Flag() : Flag::f_saved_reaction)), peer->input, MTP_string(_searchQuery), - (_searchQueryFrom - ? _searchQueryFrom->input - : MTP_inputPeerEmpty()), - MTPInputPeer(), // saved_peer_id + (fromPeer ? fromPeer->input : MTP_inputPeerEmpty()), + (savedPeer ? savedPeer->input : MTP_inputPeerEmpty()), MTP_vector_from_range( _searchQueryTags | ranges::views::transform( Data::ReactionToMTP @@ -2590,6 +2604,7 @@ bool Widget::setSearchInChat(Key chat, PeerData *from) { } const auto peer = chat.peer(); const auto topic = chat.topic(); + const auto sublist = chat.sublist(); const auto forum = peer ? peer->forum() : nullptr; if (chat.folder() || (forum && !topic)) { chat = Key(); @@ -3083,6 +3098,8 @@ void Widget::cancelSearchRequest() { PeerData *Widget::searchInPeer() const { return _openedForum ? _openedForum->channel().get() + : _searchInChat.sublist() + ? session().user().get() : _searchInChat.peer(); } diff --git a/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp b/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp index a1c9578f8..e96738d0d 100644 --- a/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp @@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_sublist_section.h" #include "main/main_session.h" +#include "core/application.h" +#include "core/shortcuts.h" #include "data/data_saved_messages.h" #include "data/data_saved_sublist.h" #include "data/data_session.h" @@ -19,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history.h" #include "history/history_item.h" #include "lang/lang_keys.h" +#include "mainwidget.h" #include "ui/chat/chat_style.h" #include "ui/widgets/buttons.h" #include "ui/widgets/scroll_area.h" @@ -115,6 +118,10 @@ SublistWidget::SublistWidget( ) | rpl::start_with_next([=] { clearSelected(); }, _topBar->lifetime()); + _topBar->searchRequest( + ) | rpl::start_with_next([=] { + searchInSublist(); + }, _topBar->lifetime()); _translateBar->raise(); _topBarShadow->raise(); @@ -134,6 +141,7 @@ SublistWidget::SublistWidget( onScroll(); }, lifetime()); + setupShortcuts(); setupTranslateBar(); } @@ -658,4 +666,24 @@ void SublistWidget::clearSelected() { _inner->cancelSelection(); } +void SublistWidget::setupShortcuts() { + Shortcuts::Requests( + ) | rpl::filter([=] { + return Ui::AppInFocus() + && Ui::InFocusChain(this) + && !controller()->isLayerShown() + && (Core::App().activeWindow() == &controller()->window()); + }) | rpl::start_with_next([=](not_null<Shortcuts::Request*> request) { + using Command = Shortcuts::Command; + request->check(Command::Search, 1) && request->handle([=] { + searchInSublist(); + return true; + }); + }, lifetime()); +} + +void SublistWidget::searchInSublist() { + controller()->content()->searchInChat(_sublist); +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_sublist_section.h b/Telegram/SourceFiles/history/view/history_view_sublist_section.h index 819ce363c..ff6d34ace 100644 --- a/Telegram/SourceFiles/history/view/history_view_sublist_section.h +++ b/Telegram/SourceFiles/history/view/history_view_sublist_section.h @@ -167,11 +167,13 @@ private: void setupOpenChatButton(); void setupAboutHiddenAuthor(); void setupTranslateBar(); + void setupShortcuts(); void confirmDeleteSelected(); void confirmForwardSelected(); void clearSelected(); void recountChatWidth(); + void searchInSublist(); const not_null<Data::SavedSublist*> _sublist; const not_null<History*> _history; diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index 891f45927..a670d8a91 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -928,7 +928,9 @@ int TopBarWidget::countSelectedButtonsTop(float64 selectedShown) { void TopBarWidget::updateSearchVisibility() { const auto searchAllowedMode = (_activeChat.section == Section::History) || (_activeChat.section == Section::Replies - && _activeChat.key.topic()); + && _activeChat.key.topic()) + || (_activeChat.section == Section::SavedSublist + && _activeChat.key.sublist()); _search->setVisible(searchAllowedMode && !_chooseForReportReason); } From 94a542a1d13cf5e49674498025ed699c475ee6b2 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 9 Jan 2024 11:17:36 +0400 Subject: [PATCH 24/73] Allow change account shortcuts in shortcuts_custom.json --- Telegram/SourceFiles/core/shortcuts.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Telegram/SourceFiles/core/shortcuts.cpp b/Telegram/SourceFiles/core/shortcuts.cpp index 56158e2b5..2d10ad484 100644 --- a/Telegram/SourceFiles/core/shortcuts.cpp +++ b/Telegram/SourceFiles/core/shortcuts.cpp @@ -133,6 +133,13 @@ const auto CommandNames = base::flat_map<Command, QString>{ { Command::FolderNext , u"next_folder"_q }, { Command::ShowAllChats , u"all_chats"_q }, + { Command::ShowAccount1 , u"account1"_q }, + { Command::ShowAccount2 , u"account2"_q }, + { Command::ShowAccount3 , u"account3"_q }, + { Command::ShowAccount4 , u"account4"_q }, + { Command::ShowAccount5 , u"account5"_q }, + { Command::ShowAccount6 , u"account6"_q }, + { Command::ShowFolder1 , u"folder1"_q }, { Command::ShowFolder2 , u"folder2"_q }, { Command::ShowFolder3 , u"folder3"_q }, From d1a0dfbb9790d86750f9d59294177ef86aae0ed1 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 9 Jan 2024 12:18:55 +0400 Subject: [PATCH 25/73] Search by tag on click in Saved Messages. --- .../data/data_message_reaction_id.cpp | 20 ++++++++++++ .../data/data_message_reaction_id.h | 7 +++++ .../dialogs/dialogs_inner_widget.cpp | 11 +++++-- .../dialogs/dialogs_inner_widget.h | 5 ++- .../dialogs/dialogs_search_tags.cpp | 31 ++++++++++++++++--- .../SourceFiles/dialogs/dialogs_search_tags.h | 4 ++- .../SourceFiles/dialogs/dialogs_widget.cpp | 27 +++++++++++----- Telegram/SourceFiles/dialogs/dialogs_widget.h | 7 +++-- .../history/view/history_view_message.cpp | 8 ++++- Telegram/lib_base | 2 +- 10 files changed, 102 insertions(+), 20 deletions(-) diff --git a/Telegram/SourceFiles/data/data_message_reaction_id.cpp b/Telegram/SourceFiles/data/data_message_reaction_id.cpp index 1103d2e15..2c1a9e503 100644 --- a/Telegram/SourceFiles/data/data_message_reaction_id.cpp +++ b/Telegram/SourceFiles/data/data_message_reaction_id.cpp @@ -11,6 +11,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Data { +QString SearchTagToQuery(const ReactionId &tagId) { + if (const auto customId = tagId.custom()) { + return u"#tag-custom:%1"_q.arg(customId); + } else if (!tagId) { + return QString(); + } + return u"#tag-emoji:"_q + tagId.emoji(); +} + +ReactionId SearchTagFromQuery(const QString &query) { + const auto list = query.split(QChar(' ')); + const auto tag = list.isEmpty() ? QString() : list[0]; + if (tag.startsWith(u"#tag-custom:"_q)) { + return ReactionId{ DocumentId(tag.mid(12).toULongLong()) }; + } else if (tag.startsWith(u"#tag-emoji:"_q)) { + return ReactionId{ tag.mid(11) }; + } + return {}; +} + QString ReactionEntityData(const ReactionId &id) { if (id.empty()) { return {}; diff --git a/Telegram/SourceFiles/data/data_message_reaction_id.h b/Telegram/SourceFiles/data/data_message_reaction_id.h index 8c50fd9de..53d4a2df8 100644 --- a/Telegram/SourceFiles/data/data_message_reaction_id.h +++ b/Telegram/SourceFiles/data/data_message_reaction_id.h @@ -27,6 +27,10 @@ struct ReactionId { return custom ? *custom : DocumentId(); } + explicit operator bool() const { + return !empty(); + } + friend inline auto operator<=>( const ReactionId &, const ReactionId &) = default; @@ -41,6 +45,9 @@ struct MessageReaction { bool my = false; }; +[[nodiscard]] QString SearchTagToQuery(const ReactionId &tagId); +[[nodiscard]] ReactionId SearchTagFromQuery(const QString &query); + [[nodiscard]] QString ReactionEntityData(const ReactionId &id); [[nodiscard]] ReactionId ReactionFromMTP(const MTPReaction &reaction); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index d809c893e..d7d17a37c 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -2968,13 +2968,17 @@ bool InnerWidget::hasFilteredResults() const { return !_filterResults.empty() && _hashtagResults.empty(); } -void InnerWidget::searchInChat(Key key, PeerData *from) { +void InnerWidget::searchInChat( + Key key, + PeerData *from, + std::vector<Data::ReactionId> tags) { _searchInMigrated = nullptr; const auto sublist = key.sublist(); const auto peer = sublist ? session().user().get() : key.peer(); if (peer) { if (const auto migrateTo = peer->migrateTo()) { - return searchInChat(peer->owner().history(migrateTo), from); + const auto to = peer->owner().history(migrateTo); + return searchInChat(to, from, tags); } else if (const auto migrateFrom = peer->migrateFrom()) { _searchInMigrated = peer->owner().history(migrateFrom); } @@ -2990,7 +2994,8 @@ void InnerWidget::searchInChat(Key key, PeerData *from) { list() ) | rpl::then( reactions->myTagsUpdates() | rpl::map(list) - )); + ), + tags); _searchTags->selectedValue( ) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index f252b7add..0f12e7211 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -139,7 +139,10 @@ public: } [[nodiscard]] bool hasFilteredResults() const; - void searchInChat(Key key, PeerData *from); + void searchInChat( + Key key, + PeerData *from, + std::vector<Data::ReactionId> tags); [[nodiscard]] auto searchTagsValue() const -> rpl::producer<std::vector<Data::ReactionId>>; diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp b/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp index 22a15ec55..7f0aa16eb 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "dialogs/dialogs_search_tags.h" +#include "base/qt/qt_key_modifiers.h" #include "data/stickers/data_custom_emoji.h" #include "data/data_document.h" #include "data/data_message_reactions.h" @@ -30,14 +31,24 @@ struct SearchTags::Tag { SearchTags::SearchTags( not_null<Data::Session*> owner, - rpl::producer<std::vector<Data::Reaction>> tags) -: _owner(owner) { + rpl::producer<std::vector<Data::Reaction>> tags, + std::vector<Data::ReactionId> selected) +: _owner(owner) +, _added(selected) { std::move( tags ) | rpl::start_with_next([=](const std::vector<Data::Reaction> &list) { fill(list); }, _lifetime); + // Mark the `selected` reactions as selected in `_tags`. + for (const auto &id : selected) { + const auto i = ranges::find(_tags, id, &Tag::id); + if (i != end(_tags)) { + i->selected = true; + } + } + style::PaletteChanged( ) | rpl::start_with_next([=] { _normalBg = _selectedBg = QImage(); @@ -54,13 +65,17 @@ void SearchTags::fill(const std::vector<Data::Reaction> &list) { return std::make_shared<LambdaClickHandler>(crl::guard(this, [=] { const auto i = ranges::find(_tags, id, &Tag::id); if (i != end(_tags)) { + if (!i->selected && !base::IsShiftPressed()) { + for (auto &tag : _tags) { + tag.selected = false; + } + } i->selected = !i->selected; _selectedChanges.fire({}); } })); }; - for (const auto &reaction : list) { - const auto id = reaction.id; + const auto push = [&](Data::ReactionId id) { const auto customId = id.custom(); _tags.push_back({ .id = id, @@ -75,6 +90,14 @@ void SearchTags::fill(const std::vector<Data::Reaction> &list) { if (!customId) { _owner->reactions().preloadImageFor(id); } + }; + for (const auto &reaction : list) { + push(reaction.id); + } + for (const auto &reaction : _added) { + if (!ranges::contains(_tags, reaction, &Tag::id)) { + push(reaction); + } } if (_width > 0) { layout(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_tags.h b/Telegram/SourceFiles/dialogs/dialogs_search_tags.h index b1c193878..4c52162eb 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_search_tags.h +++ b/Telegram/SourceFiles/dialogs/dialogs_search_tags.h @@ -25,7 +25,8 @@ class SearchTags final : public base::has_weak_ptr { public: SearchTags( not_null<Data::Session*> owner, - rpl::producer<std::vector<Data::Reaction>> tags); + rpl::producer<std::vector<Data::Reaction>> tags, + std::vector<Data::ReactionId> selected); ~SearchTags(); void resizeToWidth(int width); @@ -61,6 +62,7 @@ private: [[nodiscard]] const QImage &validateBg(bool selected) const; const not_null<Data::Session*> _owner; + std::vector<Data::ReactionId> _added; std::vector<Tag> _tags; rpl::event_stream<> _selectedChanges; rpl::event_stream<> _repaintRequests; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index eeeb09c9f..b41257487 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1911,7 +1911,7 @@ void Widget::showMainMenu() { controller()->widget()->showMainMenu(); } -void Widget::searchMessages(const QString &query, Key inChat) { +void Widget::searchMessages(QString query, Key inChat) { if (_childList) { const auto forum = controller()->shownForum().current(); const auto topic = inChat.topic(); @@ -1926,6 +1926,12 @@ void Widget::searchMessages(const QString &query, Key inChat) { controller()->closeFolder(); } + auto tags = std::vector<Data::ReactionId>(); + if (const auto tagId = Data::SearchTagFromQuery(query)) { + inChat = session().data().history(session().user()); + query = QString(); + tags.push_back(tagId); + } const auto inChatChanged = [&] { const auto inPeer = inChat.peer(); const auto inTopic = inChat.topic(); @@ -1948,10 +1954,12 @@ void Widget::searchMessages(const QString &query, Key inChat) { } return true; }(); - if ((currentSearchQuery() != query) || inChatChanged) { + if ((currentSearchQuery() != query) + || inChatChanged + || _searchTags != tags) { if (inChat) { cancelSearch(); - setSearchInChat(inChat); + setSearchInChat(inChat, nullptr, tags); } setSearchQuery(query); applyFilterUpdate(true); @@ -2595,9 +2603,12 @@ void Widget::searchInChat(Key chat) { searchMessages(QString(), chat); } -bool Widget::setSearchInChat(Key chat, PeerData *from) { +bool Widget::setSearchInChat( + Key chat, + PeerData *from, + std::vector<Data::ReactionId> tags) { if (_childList) { - if (_childList->setSearchInChat(chat, from)) { + if (_childList->setSearchInChat(chat, from, tags)) { return true; } hideChildList(); @@ -2634,7 +2645,8 @@ bool Widget::setSearchInChat(Key chat, PeerData *from) { if (_layout != Layout::Main) { return false; } else if (const auto migrateTo = peer->migrateTo()) { - return setSearchInChat(peer->owner().history(migrateTo), from); + const auto to = peer->owner().history(migrateTo); + return setSearchInChat(to, from, tags); } else if (const auto migrateFrom = peer->migrateFrom()) { _searchInMigrated = peer->owner().history(migrateFrom); } @@ -2653,7 +2665,8 @@ bool Widget::setSearchInChat(Key chat, PeerData *from) { if (_searchInChat && _layout == Layout::Main) { controller()->closeFolder(); } - _inner->searchInChat(_searchInChat, _searchFromAuthor); + _searchTags = std::move(tags); + _inner->searchInChat(_searchInChat, _searchFromAuthor, _searchTags); _searchTagsLifetime = _inner->searchTagsValue( ) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) { if (_searchTags != list) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 5ab53e2f9..3c8373cb1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -117,7 +117,7 @@ public: void scrollToEntry(const RowDescriptor &entry); - void searchMessages(const QString &query, Key inChat = {}); + void searchMessages(QString query, Key inChat = {}); void searchTopics(); void searchMore(); @@ -180,7 +180,10 @@ private: void trackScroll(not_null<Ui::RpWidget*> widget); [[nodiscard]] bool searchForPeersRequired(const QString &query) const; [[nodiscard]] bool searchForTopicsRequired(const QString &query) const; - bool setSearchInChat(Key chat, PeerData *from = nullptr); + bool setSearchInChat( + Key chat, + PeerData *from = nullptr, + std::vector<Data::ReactionId> tags = {}); void showCalendar(); void showSearchFrom(); void showMainMenu(); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index f319dfc9a..b53fb1454 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -2965,8 +2965,14 @@ void Message::refreshReactions() { if (!_reactions) { const auto handlerFactory = [=](ReactionId id) { const auto weak = base::make_weak(this); - return std::make_shared<LambdaClickHandler>([=] { + return std::make_shared<LambdaClickHandler>([=]( + ClickContext context) { if (const auto strong = weak.get()) { + if (strong->data()->reactionsAreTags()) { + const auto tag = Data::SearchTagToQuery(id); + HashtagClickHandler(tag).onClick(context); + return; + } strong->data()->toggleReaction( id, HistoryItem::ReactionSource::Existing); diff --git a/Telegram/lib_base b/Telegram/lib_base index 0d111bd46..bc78a03b1 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit 0d111bd4633324533195aa0a840730b4bf6ba75b +Subproject commit bc78a03b12b40ee6264ad2235465197b89588288 From 3c6037a79849f55e6dd269a4107aed06780940ac Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 9 Jan 2024 13:11:06 +0400 Subject: [PATCH 26/73] Custom context menu for saved-tags reactions. --- Telegram/Resources/langs/lang.strings | 4 +- .../data/data_message_reactions.cpp | 6 +- .../SourceFiles/data/data_message_reactions.h | 2 + .../view/history_view_context_menu.cpp | 63 +++++++++++++++++++ .../history_view_reactions_button.cpp | 3 +- .../reactions/history_view_reactions_button.h | 1 + 6 files changed, 75 insertions(+), 4 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 9d0707518..98055e5fc 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2749,7 +2749,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_context_seen_reacted#other" = "{count} Reacted"; "lng_context_seen_reacted_none" = "Nobody Reacted"; "lng_context_seen_reacted_all" = "Show All Reactions"; -"lng_context_set_as_quick" = "Set As Quick"; +"lng_context_set_as_quick" = "Set as Quick"; +"lng_context_filter_by_tag" = "Filter by Tag"; +"lng_context_remove_tag" = "Remove Tag"; "lng_context_delete_from_disk" = "Delete from disk"; "lng_context_delete_all_files" = "Delete all files"; "lng_context_save_custom_sound" = "Save for notifications"; diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index 9e1726b7a..4ba9c2db4 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -179,6 +179,7 @@ PossibleItemReactionsRef LookupPossibleReactions( } } result.customAllowed = premiumPossible; + result.tags = true; } else if (limited) { result.recent.reserve(all.size()); add([&](const Reaction &reaction) { @@ -243,11 +244,12 @@ PossibleItemReactionsRef LookupPossibleReactions( PossibleItemReactions::PossibleItemReactions( const PossibleItemReactionsRef &other) - : recent(other.recent | ranges::views::transform([](const auto &value) { +: recent(other.recent | ranges::views::transform([](const auto &value) { return *value; }) | ranges::to_vector) , morePremiumAvailable(other.morePremiumAvailable) -, customAllowed(other.customAllowed) { +, customAllowed(other.customAllowed) +, tags(other.tags){ } Reactions::Reactions(not_null<Session*> owner) diff --git a/Telegram/SourceFiles/data/data_message_reactions.h b/Telegram/SourceFiles/data/data_message_reactions.h index 2743bffc8..5e8721665 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.h +++ b/Telegram/SourceFiles/data/data_message_reactions.h @@ -42,6 +42,7 @@ struct PossibleItemReactionsRef { std::vector<not_null<const Reaction*>> recent; bool morePremiumAvailable = false; bool customAllowed = false; + bool tags = false; }; struct PossibleItemReactions { @@ -51,6 +52,7 @@ struct PossibleItemReactions { std::vector<Reaction> recent; bool morePremiumAvailable = false; bool customAllowed = false; + bool tags = false; }; [[nodiscard]] PossibleItemReactionsRef LookupPossibleReactions( diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index 22fcc710b..856639aa8 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -26,6 +26,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/media/history_view_web_page.h" #include "history/view/reactions/history_view_reactions_list.h" #include "ui/widgets/popup_menu.h" +#include "ui/widgets/menu/menu_action.h" +#include "ui/widgets/menu/menu_common.h" #include "ui/widgets/menu/menu_multiline_action.h" #include "ui/image/image.h" #include "ui/toast/toast.h" @@ -1293,6 +1295,62 @@ void AddWhoReactedAction( showAllChosen)); } +void ShowTagMenu( + not_null<base::unique_qptr<Ui::PopupMenu>*> menu, + QPoint position, + not_null<QWidget*> context, + not_null<HistoryItem*> item, + const Data::ReactionId &id, + not_null<Window::SessionController*> controller) { + using namespace Data; + const auto itemId = item->fullId(); + const auto owner = &controller->session().data(); + *menu = base::make_unique_q<Ui::PopupMenu>( + context, + st::popupMenuExpandedSeparator); + (*menu)->addAction(tr::lng_context_filter_by_tag(tr::now), [=] { + HashtagClickHandler(SearchTagToQuery(id)).onClick({ + .button = Qt::LeftButton, + .other = QVariant::fromValue(ClickHandlerContext{ + .sessionWindow = controller, + }), + }); + }, &st::menuIconFave); + + const auto removeTag = [=] { + if (const auto item = owner->message(itemId)) { + const auto &list = item->reactions(); + if (ranges::contains(list, id, &MessageReaction::id)) { + item->toggleReaction( + id, + HistoryItem::ReactionSource::Quick); + } + } + }; + (*menu)->addAction(base::make_unique_q<Ui::Menu::Action>( + (*menu)->menu(), + st::menuWithIconsAttention, + Ui::Menu::CreateAction( + (*menu)->menu(), + tr::lng_context_remove_tag(tr::now), + removeTag), + &st::menuIconDisableAttention, + &st::menuIconDisableAttention)); + + if (const auto custom = id.custom()) { + if (const auto set = owner->document(custom)->sticker()) { + if (set->set.id) { + AddEmojiPacksAction( + menu->get(), + { set->set }, + EmojiPacksSource::Reaction, + controller); + } + } + } + (*menu)->popup(position); +} + void ShowWhoReactedMenu( not_null<base::unique_qptr<Ui::PopupMenu>*> menu, QPoint position, @@ -1301,6 +1359,11 @@ void ShowWhoReactedMenu( const Data::ReactionId &id, not_null<Window::SessionController*> controller, rpl::lifetime &lifetime) { + if (item->reactionsAreTags()) { + ShowTagMenu(menu, position, context, item, id, controller); + return; + } + struct State { int addedToBottom = 0; }; diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp index 2081a85e7..171ad9d03 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp @@ -451,6 +451,7 @@ void Manager::applyList(const Data::PossibleItemReactionsRef &reactions) { : reactions.morePremiumAvailable ? Button::Premium : */Button::None)); + _tagsStrip = reactions.tags; } QMargins Manager::innerMargins() const { @@ -814,7 +815,7 @@ bool Manager::showContextMenu( const ReactionId &favorite) { const auto selected = _strip.selected(); const auto id = std::get_if<ReactionId>(&selected); - if (!id || id->empty()) { + if (!id || id->empty() || _tagsStrip) { return false; } else if (*id == favorite) { return true; diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.h b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.h index 793382198..eb9c7fc5d 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.h +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.h @@ -235,6 +235,7 @@ private: rpl::variable<int> _uniqueLimit = 0; bool _showingAll = false; + bool _tagsStrip = false; std::optional<ButtonParameters> _scheduledParameters; base::Timer _buttonShowTimer; From 4471eb587d9091ffeb9e115d51001e53a60d0a19 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 9 Jan 2024 13:11:25 +0400 Subject: [PATCH 27/73] Fix possible crash in gift box sticker lookup. --- Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp index e20c361d6..f54b1f1d3 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_gift_box_pack.cpp @@ -26,6 +26,8 @@ DocumentData *GiftBoxPack::lookup(int months) const { const auto fallback = _documents.empty() ? nullptr : _documents[0]; if (it == begin(_localMonths)) { return fallback; + } else if (it == end(_localMonths)) { + return _documents.back(); } const auto left = *(it - 1); const auto right = *it; From 9401e7cb515896d110810ce9181c5903e7871e73 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 9 Jan 2024 17:51:29 +0400 Subject: [PATCH 28/73] Add "View reactions" phrase to the langpack. --- Telegram/Resources/langs/lang.strings | 1 + .../SourceFiles/media/stories/media_stories_recent_views.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 98055e5fc..347fdbdc7 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4348,6 +4348,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_stories_views#one" = "{count} view"; "lng_stories_views#other" = "{count} views"; "lng_stories_no_views" = "No views"; +"lng_stories_view_reactions" = "View reactions"; "lng_stories_unsupported" = "This story is not supported\nby your version of Telegram."; "lng_stories_cant_reply" = "You can't reply to this story."; "lng_stories_about_silent" = "This video has no sound."; diff --git a/Telegram/SourceFiles/media/stories/media_stories_recent_views.cpp b/Telegram/SourceFiles/media/stories/media_stories_recent_views.cpp index 2521de47f..442199300 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_recent_views.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_recent_views.cpp @@ -421,7 +421,7 @@ void RecentViews::updatePartsGeometry() { void RecentViews::updateText() { const auto text = (_data.type == RecentViewsType::Channel) - ? u"View reactions"_q + ? tr::lng_stories_view_reactions(tr::now) : _data.views ? (tr::lng_stories_views(tr::now, lt_count, _data.views) + (_data.reactions From e2439984ae486c7fff6f634a5273028bc51f64ff Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 9 Jan 2024 21:51:05 -0800 Subject: [PATCH 29/73] Pass whole point in mapFromGlobal(mapToGlobal). Fixes #27237. --- .../history/admin_log/history_admin_log_inner.cpp | 6 +++--- .../SourceFiles/history/history_inner_widget.cpp | 12 +++++++----- .../history/view/history_view_list_widget.cpp | 6 +++--- .../SourceFiles/window/window_session_controller.cpp | 2 +- .../SourceFiles/window/window_session_controller.h | 6 +++--- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index fb6f950e0..2598e1f36 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -943,10 +943,10 @@ void InnerWidget::paintEvent(QPaintEvent *e) { auto clip = e->rect(); auto context = _controller->preparePaintContext({ .theme = _theme.get(), - .visibleAreaTop = _visibleTop, - .visibleAreaTopGlobal = mapToGlobal(QPoint(0, _visibleTop)).y(), - .visibleAreaWidth = width(), .clip = clip, + .visibleAreaPositionGlobal = mapToGlobal(QPoint(0, _visibleTop)), + .visibleAreaTop = _visibleTop, + .visibleAreaWidth = width(), }); if (_items.empty() && _upLoaded && _downLoaded) { paintEmpty(p, context.st); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 353bb6870..c824976cf 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -979,14 +979,16 @@ void HistoryInner::paintEmpty( Ui::ChatPaintContext HistoryInner::preparePaintContext( const QRect &clip) const { - const auto visibleAreaTopGlobal = mapToGlobal( - QPoint(0, _visibleAreaTop)).y(); + const auto visibleAreaPositionGlobal = mapToGlobal( + QPoint(0, _visibleAreaTop)); + const auto visibleAreaPositionLocal = mapFromGlobal( + visibleAreaPositionGlobal); return _controller->preparePaintContext({ .theme = _theme.get(), - .visibleAreaTop = _visibleAreaTop, - .visibleAreaTopGlobal = visibleAreaTopGlobal, - .visibleAreaWidth = width(), .clip = clip, + .visibleAreaPositionGlobal = visibleAreaPositionGlobal, + .visibleAreaTop = _visibleAreaTop, + .visibleAreaWidth = width(), }); } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 50822615c..984cc0e79 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2009,10 +2009,10 @@ Ui::ChatPaintContext ListWidget::preparePaintContext( const QRect &clip) const { return controller()->preparePaintContext({ .theme = _delegate->listChatTheme(), - .visibleAreaTop = _visibleTop, - .visibleAreaTopGlobal = mapToGlobal(QPoint(0, _visibleTop)).y(), - .visibleAreaWidth = width(), .clip = clip, + .visibleAreaPositionGlobal = mapToGlobal(QPoint(0, _visibleTop)), + .visibleAreaTop = _visibleTop, + .visibleAreaWidth = width(), }); } diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 3f78e1850..b4be01c6d 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -2742,7 +2742,7 @@ void SessionController::openPeerStories( HistoryView::PaintContext SessionController::preparePaintContext( PaintContextArgs &&args) { const auto visibleAreaTopLocal = content()->mapFromGlobal( - QPoint(0, args.visibleAreaTopGlobal)).y(); + args.visibleAreaPositionGlobal).y(); const auto viewport = QRect( 0, args.visibleAreaTop - visibleAreaTopLocal, diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 4ef7b1791..d3452c8ca 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -565,10 +565,10 @@ public: struct PaintContextArgs { not_null<Ui::ChatTheme*> theme; - int visibleAreaTop = 0; - int visibleAreaTopGlobal = 0; - int visibleAreaWidth = 0; QRect clip; + QPoint visibleAreaPositionGlobal; + int visibleAreaTop = 0; + int visibleAreaWidth = 0; }; [[nodiscard]] Ui::ChatPaintContext preparePaintContext( PaintContextArgs &&args); From 0dfe37f998b42ca095fd357d835e4255ec1011a7 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Wed, 10 Jan 2024 08:28:39 -0800 Subject: [PATCH 30/73] Mirror my outgoing video in video chats. --- .../SourceFiles/calls/calls_video_bubble.cpp | 16 ++++++++-------- .../calls/group/calls_group_panel.cpp | 4 +++- .../calls/group/calls_group_viewport.cpp | 6 ++++-- .../calls/group/calls_group_viewport.h | 3 ++- .../calls/group/calls_group_viewport_opengl.cpp | 6 ++++++ .../calls/group/calls_group_viewport_raster.cpp | 4 ++-- .../calls/group/calls_group_viewport_tile.cpp | 10 ++++++++-- .../calls/group/calls_group_viewport_tile.h | 8 +++++++- 8 files changed, 40 insertions(+), 17 deletions(-) diff --git a/Telegram/SourceFiles/calls/calls_video_bubble.cpp b/Telegram/SourceFiles/calls/calls_video_bubble.cpp index aecabfd55..043ee8c41 100644 --- a/Telegram/SourceFiles/calls/calls_video_bubble.cpp +++ b/Telegram/SourceFiles/calls/calls_video_bubble.cpp @@ -127,12 +127,13 @@ void VideoBubble::paint() { const auto inner = _content.rect().marginsRemoved(padding); Ui::Shadow::paint(p, inner, _content.width(), st::boxRoundShadow); const auto factor = cIntRetinaFactor(); + const auto left = _mirrored + ? (_frame.width() - (inner.width() * factor)) + : 0; p.drawImage( inner, _frame, - QRect( - QPoint(_frame.width() - (inner.width() * factor), 0), - inner.size() * factor)); + QRect(QPoint(left, 0), inner.size() * factor)); } _track->markFrameShown(); } @@ -152,11 +153,10 @@ void VideoBubble::prepareFrame() { .resize = size, .outer = size, }; - const auto frame = _track->frame(request).mirrored(!_mirrored, false); + const auto frame = _track->frame(request); if (_frame.width() < size.width() || _frame.height() < size.height()) { - _frame = QImage( - size * cIntRetinaFactor(), - QImage::Format_ARGB32_Premultiplied); + _frame = QImage(size, QImage::Format_ARGB32_Premultiplied); + _frame.fill(Qt::transparent); } Assert(_frame.width() >= frame.width() && _frame.height() >= frame.height()); @@ -174,7 +174,7 @@ void VideoBubble::prepareFrame() { ImageRoundRadius::Large, RectPart::AllCorners, QRect(QPoint(), size) - ).mirrored(true, false); + ).mirrored(_mirrored, false); } void VideoBubble::setState(Webrtc::VideoState state) { diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index d3bac6aeb..6455ad040 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -1060,11 +1060,13 @@ void Panel::setupVideo(not_null<Viewport*> viewport) { _call->videoEndpointLargeValue(), _call->videoEndpointPinnedValue() ) | rpl::map(_1 == endpoint && _2); + const auto self = (endpoint.peer == _call->joinAs()); viewport->add( endpoint, VideoTileTrack{ GroupCall::TrackPointer(track), row }, GroupCall::TrackSizeValue(track), - std::move(pinned)); + std::move(pinned), + self); }; for (const auto &[endpoint, track] : _call->activeVideoTracks()) { setupTile(endpoint, track); diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp index 48c76d0ae..9623171b9 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp @@ -237,13 +237,15 @@ void Viewport::add( const VideoEndpoint &endpoint, VideoTileTrack track, rpl::producer<QSize> trackSize, - rpl::producer<bool> pinned) { + rpl::producer<bool> pinned, + bool self) { _tiles.push_back(std::make_unique<VideoTile>( endpoint, track, std::move(trackSize), std::move(pinned), - [=] { widget()->update(); })); + [=] { widget()->update(); }, + self)); _tiles.back()->trackSizeValue( ) | rpl::filter([](QSize size) { diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport.h b/Telegram/SourceFiles/calls/group/calls_group_viewport.h index c6567e037..9d5021f85 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport.h +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport.h @@ -80,7 +80,8 @@ public: const VideoEndpoint &endpoint, VideoTileTrack track, rpl::producer<QSize> trackSize, - rpl::producer<bool> pinned); + rpl::producer<bool> pinned, + bool self); void remove(const VideoEndpoint &endpoint); void showLarge(const VideoEndpoint &endpoint); diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp index 946c6dca8..e11644e68 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp @@ -531,6 +531,12 @@ void Viewport::RendererGL::paintTile( { { 1.f, 0.f } }, { { 0.f, 0.f } }, } }; + if (tile->mirror()) { + std::swap(toBlurTexCoords[0], toBlurTexCoords[1]); + std::swap(toBlurTexCoords[2], toBlurTexCoords[3]); + std::swap(texCoords[0], texCoords[1]); + std::swap(texCoords[2], texCoords[3]); + } if (const auto shift = (frameRotation / 90); shift > 0) { std::rotate( toBlurTexCoords.begin(), diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp index f85929ea1..ab335c55c 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp @@ -105,14 +105,14 @@ void Viewport::RendererSW::paintTile( tileData.blurredFrame = Images::BlurLargeImage( data.original.scaled( VideoTile::PausedVideoSize(), - Qt::KeepAspectRatio), + Qt::KeepAspectRatio).mirrored(tile->mirror(), false), kBlurRadius); } const auto &image = _userpicFrame ? tileData.userpicFrame : _pausedFrame ? tileData.blurredFrame - : data.original; + : data.original.mirrored(tile->mirror(), false); const auto frameRotation = _userpicFrame ? 0 : data.rotation; Assert(!image.isNull()); diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp index 58ac0fb9d..1b31a2012 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp @@ -28,12 +28,14 @@ Viewport::VideoTile::VideoTile( VideoTileTrack track, rpl::producer<QSize> trackSize, rpl::producer<bool> pinned, - Fn<void()> update) + Fn<void()> update, + bool self) : _endpoint(endpoint) , _update(std::move(update)) , _track(std::move(track)) , _trackSize(std::move(trackSize)) -, _rtmp(endpoint.rtmp()) { +, _rtmp(endpoint.rtmp()) +, _self(self) { Expects(_track.track != nullptr); Expects(_track.row != nullptr); @@ -48,6 +50,10 @@ Viewport::VideoTile::VideoTile( setup(std::move(pinned)); } +bool Viewport::VideoTile::mirror() const { + return _self && (_endpoint.type == VideoEndpointType::Camera); +} + QRect Viewport::VideoTile::pinOuter() const { return _pinOuter; } diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h index 445bf2d7e..6f85f4a01 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h @@ -28,7 +28,8 @@ public: VideoTileTrack track, rpl::producer<QSize> trackSize, rpl::producer<bool> pinned, - Fn<void()> update); + Fn<void()> update, + bool self); [[nodiscard]] not_null<Webrtc::VideoTrack*> track() const { return _track.track; @@ -54,6 +55,10 @@ public: [[nodiscard]] bool visible() const { return !_hidden && !_geometry.isEmpty(); } + [[nodiscard]] bool self() const { + return _self; + } + [[nodiscard]] bool mirror() const; [[nodiscard]] QRect pinOuter() const; [[nodiscard]] QRect pinInner() const; [[nodiscard]] QRect backOuter() const; @@ -123,6 +128,7 @@ private: bool _pinned = false; bool _hidden = true; bool _rtmp = false; + bool _self = false; std::optional<VideoQuality> _quality; rpl::lifetime _lifetime; From 3eefaac8857852add4c36e6b984f437e14ebcc5c Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Wed, 10 Jan 2024 09:54:30 -0800 Subject: [PATCH 31/73] Fix screen sharing source choose window. --- .../calls/group/ui/desktop_capture_choose_source.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/calls/group/ui/desktop_capture_choose_source.cpp b/Telegram/SourceFiles/calls/group/ui/desktop_capture_choose_source.cpp index 87ac643d3..ad59290c5 100644 --- a/Telegram/SourceFiles/calls/group/ui/desktop_capture_choose_source.cpp +++ b/Telegram/SourceFiles/calls/group/ui/desktop_capture_choose_source.cpp @@ -114,6 +114,7 @@ private: const not_null<RoundButton*> _finish; const not_null<Checkbox*> _withAudio; + QSize _fixedSize; std::vector<std::unique_ptr<Source>> _sources; Source *_selected = nullptr; QString _selectedId; @@ -337,7 +338,7 @@ void ChooseSourceProcess::setupPanel() { + (kRows - 1) * skips.height() + (st::desktopCaptureSourceSize.height() / 2) + bottomHeight; - _window->setFixedSize({ width, height }); + _fixedSize = QSize(width, height); _window->setStaysOnTop(true); _window->body()->paintRequest( @@ -598,6 +599,7 @@ void ChooseSourceProcess::setupGeometryWithParent( if (parentScreen && myScreen != parentScreen) { _window->windowHandle()->setScreen(parentScreen); } + _window->setFixedSize(_fixedSize); _window->move( parent->x() + (parent->width() - _window->width()) / 2, parent->y() + (parent->height() - _window->height()) / 2); From fc2f41096fafc620c4cdde84797d9ce471a0169f Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Fri, 12 Jan 2024 13:57:47 +0400 Subject: [PATCH 32/73] Attempt to fix initial window position on Windows. --- Telegram/SourceFiles/core/application.cpp | 2 +- Telegram/SourceFiles/window/main_window.cpp | 5 +++-- Telegram/SourceFiles/window/main_window.h | 2 +- Telegram/SourceFiles/window/window_controller.cpp | 4 ++++ Telegram/SourceFiles/window/window_controller.h | 1 + Telegram/lib_ui | 2 +- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 399246973..998793df3 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -360,7 +360,7 @@ void Application::run() { startDomain(); startTray(); - _lastActivePrimaryWindow->widget()->show(); + _lastActivePrimaryWindow->firstShow(); startMediaView(); diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index d25992051..3f8c9b5ba 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -475,7 +475,6 @@ void MainWindow::init() { } refreshTitleWidget(); - initGeometry(); updateTitle(); updateWindowIcon(); } @@ -772,9 +771,10 @@ QRect MainWindow::countInitialGeometry( return position.rect(); } -void MainWindow::initGeometry() { +void MainWindow::firstShow() { updateMinimumSize(); if (initGeometryFromSystem()) { + show(); return; } const auto geometry = countInitialGeometry(initialPosition()); @@ -784,6 +784,7 @@ void MainWindow::initGeometry() { ).arg(geometry.width() ).arg(geometry.height())); setGeometry(geometry); + show(); } void MainWindow::positionUpdated() { diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index e59967e80..8feb329a9 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -132,6 +132,7 @@ public: void recountGeometryConstraints(); virtual void updateControlsGeometry(); + void firstShow(); bool minimizeToTray(); void updateGlobalMenu() { updateGlobalMenuHook(); @@ -197,7 +198,6 @@ private: [[nodiscard]] Core::WindowPosition nextInitialChildPosition( bool primary); [[nodiscard]] QRect countInitialGeometry(Core::WindowPosition position); - void initGeometry(); bool computeIsActive() const; diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index 917cd6d66..19c12c30e 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -311,6 +311,10 @@ void Controller::showTermsDelete() { })); } +void Controller::firstShow() { + _widget.firstShow(); +} + void Controller::finishFirstShow() { _widget.finishFirstShow(); checkThemeEditor(); diff --git a/Telegram/SourceFiles/window/window_controller.h b/Telegram/SourceFiles/window/window_controller.h index 36c35979e..cd5979006 100644 --- a/Telegram/SourceFiles/window/window_controller.h +++ b/Telegram/SourceFiles/window/window_controller.h @@ -74,6 +74,7 @@ public: [[nodiscard]] Adaptive &adaptive() const; + void firstShow(); void finishFirstShow(); void setupPasscodeLock(); diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 00f5bdacc..aa39793a9 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 00f5bdaccdff4f53e8ba347f09f2de161b7ca7da +Subproject commit aa39793a91f1186879c15c214a2671d78eab5085 From f8caa02f108d40358bfe5f4cc87cc6229d630058 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Fri, 12 Jan 2024 13:58:12 +0400 Subject: [PATCH 33/73] Fix animating list->chat transition in single column. --- Telegram/SourceFiles/mainwidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index fe92a6de1..fef1fb39c 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1524,7 +1524,9 @@ bool MainWidget::saveSectionInStack( _history->msgId(), _history->replyReturns())); } else { - return false; + // We pretend that we "saved" the chats list state in stack, + // so that we do animate a transition from chats list to a section. + return true; } const auto raw = _stack.back().get(); raw->setThirdSectionWeak(_thirdSection.data()); From 37067f17e2523256daab3fa16e9d565262586185 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 9 Jan 2024 14:49:35 +0300 Subject: [PATCH 34/73] Added new viewer widget for voice messages with ttl. --- Telegram/CMakeLists.txt | 2 + Telegram/Resources/langs/lang.strings | 3 + .../chat_helpers/chat_helpers.style | 14 + .../chat_helpers/ttl_media_layer_widget.cpp | 273 ++++++++++++++++++ .../chat_helpers/ttl_media_layer_widget.h | 22 ++ .../data/data_document_resolver.cpp | 15 +- .../history/view/history_view_element.h | 1 + .../history/view/history_view_message.cpp | 4 +- .../view/media/history_view_document.cpp | 77 +++-- .../view/media/history_view_document.h | 2 + 10 files changed, 379 insertions(+), 34 deletions(-) create mode 100644 Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp create mode 100644 Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 59c701340..b1fc1570d 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -406,6 +406,8 @@ PRIVATE chat_helpers/tabbed_section.h chat_helpers/tabbed_selector.cpp chat_helpers/tabbed_selector.h + chat_helpers/ttl_media_layer_widget.cpp + chat_helpers/ttl_media_layer_widget.h core/application.cpp core/application.h core/base_integration.cpp diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 347fdbdc7..cec8bf36e 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1719,6 +1719,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_ttl_voice_expired" = "Voice message expired"; "lng_ttl_round_sent" = "You sent a self-destructing video message."; "lng_ttl_round_expired" = "Round message expired"; +"lng_ttl_voice_tooltip_in" = "This voice message can only be played once."; +"lng_ttl_voice_tooltip_out" = "This message will disappear once **{user}** plays it once."; +"lng_ttl_voice_close_in" = "Delete and close"; "lng_profile_add_more_after_create" = "You will be able to add more members after you create the group."; "lng_profile_camera_title" = "Capture yourself"; diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index c86e98b75..a7f94d301 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -1266,3 +1266,17 @@ dragDropColor: windowActiveTextFg; dragMargin: margins(0px, 10px, 0px, 10px); dragPadding: margins(20px, 10px, 20px, 10px); dragHeight: 72px; + +ttlMediaImportantTooltipLabel: FlatLabel(defaultImportantTooltipLabel) { + style: TextStyle(defaultTextStyle) { + font: font(14px); + } +} +ttlMediaButton: RoundButton(defaultActiveButton) { + textBg: shadowFg; + textBgOver: shadowFg; + ripple: universalRippleAnimation; + height: 31px; + textTop: 6px; +} +ttlMediaButtonBottomSkip: 14px; diff --git a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp new file mode 100644 index 000000000..91403a2c2 --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp @@ -0,0 +1,273 @@ +/* +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 "chat_helpers/ttl_media_layer_widget.h" + +#include "base/event_filter.h" +#include "data/data_session.h" +#include "editor/editor_layer_widget.h" +#include "history/history.h" +#include "history/history_item.h" +#include "history/view/history_view_element.h" +#include "history/view/media/history_view_document.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "mainwidget.h" +#include "media/audio/media_audio.h" +#include "media/player/media_player_instance.h" +#include "ui/chat/chat_style.h" +#include "ui/chat/chat_theme.h" +#include "ui/effects/path_shift_gradient.h" +#include "ui/painter.h" +#include "ui/text/text_utilities.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/labels.h" +#include "ui/widgets/tooltip.h" +#include "window/themes/window_theme.h" +#include "window/window_session_controller.h" +#include "styles/style_chat.h" +#include "styles/style_chat_helpers.h" +#include "styles/style_dialogs.h" + +namespace ChatHelpers { +namespace { + +class PreviewDelegate final : public HistoryView::DefaultElementDelegate { +public: + PreviewDelegate( + not_null<QWidget*> parent, + not_null<Ui::ChatStyle*> st, + Fn<void()> update); + + bool elementAnimationsPaused() override; + not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override; + HistoryView::Context elementContext() override; + bool elementIsChatWide() override; + +private: + const not_null<QWidget*> _parent; + const std::unique_ptr<Ui::PathShiftGradient> _pathGradient; + +}; + +PreviewDelegate::PreviewDelegate( + not_null<QWidget*> parent, + not_null<Ui::ChatStyle*> st, + Fn<void()> update) +: _parent(parent) +, _pathGradient(HistoryView::MakePathShiftGradient(st, update)) { +} + +bool PreviewDelegate::elementAnimationsPaused() { + return _parent->window()->isActiveWindow(); +} + +not_null<Ui::PathShiftGradient*> PreviewDelegate::elementPathShiftGradient() { + return _pathGradient.get(); +} + +HistoryView::Context PreviewDelegate::elementContext() { + return HistoryView::Context::TTLViewer; +} + +bool PreviewDelegate::elementIsChatWide() { + return true; +} + +class PreviewWrap final : public Ui::RpWidget { +public: + PreviewWrap(not_null<Ui::RpWidget*> parent, not_null<HistoryItem*> item); + ~PreviewWrap(); + + [[nodiscard]] rpl::producer<> closeRequests() const; + +private: + void paintEvent(QPaintEvent *e) override; + [[nodiscard]] QRect elementRect() const; + + const not_null<HistoryItem*> _item; + const std::unique_ptr<Ui::ChatTheme> _theme; + const std::unique_ptr<Ui::ChatStyle> _style; + const std::unique_ptr<PreviewDelegate> _delegate; + std::unique_ptr<HistoryView::Element> _element; + rpl::lifetime _elementLifetime; + + rpl::event_stream<> _closeRequests; + +}; + +PreviewWrap::PreviewWrap( + not_null<Ui::RpWidget*> parent, + not_null<HistoryItem*> item) +: RpWidget(parent) +, _item(item) +, _theme(Window::Theme::DefaultChatThemeOn(lifetime())) +, _style(std::make_unique<Ui::ChatStyle>( + item->history()->session().colorIndicesValue())) +, _delegate(std::make_unique<PreviewDelegate>( + parent, + _style.get(), + [=] { update(elementRect()); })) { + _style->apply(_theme.get()); + + const auto session = &_item->history()->session(); + session->data().viewRepaintRequest( + ) | rpl::start_with_next([=](not_null<const HistoryView::Element*> view) { + if (view == _element.get()) { + update(elementRect()); + } + }, lifetime()); + + const auto closeCallback = [=] { _closeRequests.fire({}); }; + + { + const auto close = Ui::CreateChild<Ui::RoundButton>( + this, + item->out() + ? tr::lng_close() + : tr::lng_ttl_voice_close_in(), + st::ttlMediaButton); + close->setFullRadius(true); + close->setClickedCallback(closeCallback); + close->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); + + sizeValue( + ) | rpl::start_with_next([=](const QSize &s) { + close->moveToLeft( + (s.width() - close->width()) / 2, + s.height() - close->height() - st::ttlMediaButtonBottomSkip); + }, close->lifetime()); + } + + QWidget::setAttribute(Qt::WA_OpaquePaintEvent, false); + _element = _item->createView(_delegate.get()); + + { + _element->initDimensions(); + widthValue( + ) | rpl::filter([=](int width) { + return width > st::msgMinWidth; + }) | rpl::start_with_next([=](int width) { + _element->resizeGetHeight(width); + }, _elementLifetime); + } + + { + auto text = item->out() + ? tr::lng_ttl_voice_tooltip_out( + lt_user, + rpl::single( + item->history()->peer->name() + ) | rpl::map(Ui::Text::RichLangValue), + Ui::Text::RichLangValue) + : tr::lng_ttl_voice_tooltip_in(Ui::Text::RichLangValue); + const auto tooltip = Ui::CreateChild<Ui::ImportantTooltip>( + this, + object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>( + this, + Ui::MakeNiceTooltipLabel( + parent, + std::move(text), + st::dialogsStoriesTooltipMaxWidth, + st::ttlMediaImportantTooltipLabel), + st::defaultImportantTooltip.padding), + st::dialogsStoriesTooltip); + tooltip->toggleFast(true); + sizeValue( + ) | rpl::filter( + [](const QSize &s) { return !s.isNull(); } + ) | rpl::take(1) | rpl::start_with_next([=](const QSize &s) { + if (s.isEmpty()) { + return; + } + auto area = elementRect(); + area.setWidth(_element->media() + ? _element->media()->width() + : _element->width()); + tooltip->pointAt(area, RectPart::Top, [=](QSize size) { + return QPoint{ + (area.width() - size.width()) / 2, + (s.height() - size.height() * 2 - _element->height()) / 2 + - st::defaultImportantTooltip.padding.top(), + }; + }); + }, tooltip->lifetime()); + } + + HistoryView::TTLVoiceStops( + item->fullId() + ) | rpl::start_with_next(closeCallback, lifetime()); +} + +QRect PreviewWrap::elementRect() const { + return QRect( + (width() - _element->width()) / 2, + (height() - _element->height()) / 2, + _element->width(), + _element->height()); +} + +rpl::producer<> PreviewWrap::closeRequests() const { + return _closeRequests.events(); +} + +PreviewWrap::~PreviewWrap() { + _elementLifetime.destroy(); + _element = nullptr; +} + +void PreviewWrap::paintEvent(QPaintEvent *e) { + if (!_element) { + return; + } + + auto p = Painter(this); + const auto r = rect(); + + auto context = _theme->preparePaintContext( + _style.get(), + r, + e->rect(), + !window()->isActiveWindow()); + context.outbg = _element->hasOutLayout(); + + p.translate( + (r.width() - _element->width()) / 2, + (r.height() - _element->height()) / 2); + _element->draw(p, context); +} + +} // namespace + +void ShowTTLMediaLayerWidget( + not_null<Window::SessionController*> controller, + not_null<HistoryItem*> item) { + const auto parent = controller->content(); + const auto show = controller->uiShow(); + auto preview = base::make_unique_q<PreviewWrap>(parent, item); + preview->closeRequests( + ) | rpl::start_with_next([=] { + show->hideLayer(); + }, preview->lifetime()); + auto layer = std::make_unique<Editor::LayerWidget>( + parent, + std::move(preview)); + layer->lifetime().add([] { ::Media::Player::instance()->stop(); }); + base::install_event_filter(layer.get(), [=](not_null<QEvent*> e) { + if (e->type() == QEvent::KeyPress) { + const auto k = static_cast<QKeyEvent*>(e.get()); + if (k->key() == Qt::Key_Escape) { + show->hideLayer(); + } + return base::EventFilterResult::Cancel; + } + return base::EventFilterResult::Continue; + }); + controller->showLayer(std::move(layer), Ui::LayerOption::KeepOther); +} + +} // namespace ChatHelpers diff --git a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.h b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.h new file mode 100644 index 000000000..f31d04982 --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.h @@ -0,0 +1,22 @@ +/* +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 + +class HistoryItem; + +namespace Window { +class SessionController; +} // namespace Window + +namespace ChatHelpers { + +void ShowTTLMediaLayerWidget( + not_null<Window::SessionController*> controller, + not_null<HistoryItem*> item); + +} // namespace ChatHelpers diff --git a/Telegram/SourceFiles/data/data_document_resolver.cpp b/Telegram/SourceFiles/data/data_document_resolver.cpp index 2c34719ff..8ab502564 100644 --- a/Telegram/SourceFiles/data/data_document_resolver.cpp +++ b/Telegram/SourceFiles/data/data_document_resolver.cpp @@ -9,7 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/options.h" #include "base/platform/base_platform_info.h" -#include "ui/boxes/confirm_box.h" +#include "boxes/abstract_box.h" // Ui::show(). +#include "chat_helpers/ttl_media_layer_widget.h" #include "core/application.h" #include "core/core_settings.h" #include "core/mime_type.h" @@ -17,17 +18,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_document_media.h" #include "data/data_file_click_handler.h" #include "data/data_session.h" -#include "history/view/media/history_view_gif.h" #include "history/history.h" #include "history/history_item.h" -#include "media/player/media_player_instance.h" +#include "history/view/media/history_view_gif.h" #include "lang/lang_keys.h" +#include "media/player/media_player_instance.h" #include "platform/platform_file_utilities.h" +#include "ui/boxes/confirm_box.h" #include "ui/chat/chat_theme.h" #include "ui/text/text_utilities.h" #include "ui/widgets/checkbox.h" #include "window/window_session_controller.h" -#include "boxes/abstract_box.h" // Ui::show(). #include "styles/style_layers.h" #include <QtCore/QBuffer> @@ -298,6 +299,12 @@ void ResolveDocument( || document->isVoiceMessage() || document->isVideoMessage()) { ::Media::Player::instance()->playPause({ document, msgId }); + if (controller + && item + && item->media() + && item->media()->ttlSeconds()) { + ChatHelpers::ShowTTLMediaLayerWidget(controller, item); + } } else { showDocument(); } diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 3b524915f..134a7bf70 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -58,6 +58,7 @@ enum class Context : char { AdminLog, ContactPreview, SavedSublist, + TTLViewer, }; enum class OnlyEmojiAndSpaces : char { diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index b53fb1454..d7c9e2f16 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -2005,6 +2005,7 @@ bool Message::hasFromPhoto() const { return !item->out() && !item->history()->peer->isUser(); } break; case Context::ContactPreview: + case Context::TTLViewer: return false; } Unexpected("Context in Message::hasFromPhoto."); @@ -3200,9 +3201,10 @@ bool Message::hasFromName() const { return false; } break; case Context::ContactPreview: + case Context::TTLViewer: return false; } - Unexpected("Context in Message::hasFromPhoto."); + Unexpected("Context in Message::hasFromName."); } bool Message::displayFromName() const { diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 7ca7bc747..2dc91de74 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -134,7 +134,11 @@ void DrawCornerBadgeTTL( }); animate(animate); }); + const auto weak = std::weak_ptr(lifetime); return [=](QPainter &p, QRect r, QColor c) { + if (weak.expired()) { + return; + } (state->idle ? state->idle : state->start)->paintInCenter(p, r, c); }; } @@ -326,41 +330,36 @@ Document::Document( } if ((_data->isVoiceMessage() || isRound) - && IsVoiceOncePlayable(_parent->data())) { - _parent->data()->removeFromSharedMediaIndex(); - setDocumentLinks(_data, realParent, [=] { - _openl = nullptr; - + && _parent->data()->media()->ttlSeconds()) { + const auto fullId = _realParent->fullId(); + if (_parent->delegate()->elementContext() == Context::TTLViewer) { auto lifetime = std::make_shared<rpl::lifetime>(); - rpl::merge( - ::Media::Player::instance()->updatedNotifier( - ) | rpl::filter([=](::Media::Player::TrackState state) { - using State = ::Media::Player::State; - const auto badState = state.state == State::Stopped - || state.state == State::StoppedAtEnd - || state.state == State::StoppedAtError - || state.state == State::StoppedAtStart; - return (state.id.contextId() != _realParent->fullId()) - && !badState; - }) | rpl::to_empty, - ::Media::Player::instance()->tracksFinished( - ) | rpl::filter([=](AudioMsgId::Type type) { - return (type == AudioMsgId::Type::Voice); - }) | rpl::to_empty, - ::Media::Player::instance()->stops(AudioMsgId::Type::Voice) - ) | rpl::start_with_next([=]() mutable { - _drawTtl = nullptr; - const auto item = _parent->data(); + TTLVoiceStops(fullId) | rpl::start_with_next([=]() mutable { if (lifetime) { base::take(lifetime)->destroy(); } - // Destroys this. - ClearMediaAsExpired(item); }, *lifetime); _drawTtl = CreateTtlPaintCallback(lifetime, [=] { repaint(); }); + } else if (!_parent->data()->out()) { + _parent->data()->removeFromSharedMediaIndex(); + setDocumentLinks(_data, realParent, [=] { + _openl = nullptr; - return false; - }); + auto lifetime = std::make_shared<rpl::lifetime>(); + TTLVoiceStops(fullId) | rpl::start_with_next([=]() mutable { + const auto item = _parent->data(); + if (lifetime) { + base::take(lifetime)->destroy(); + } + // Destroys this. + ClearMediaAsExpired(item); + }, *lifetime); + + return false; + }); + } else { + setDocumentLinks(_data, realParent); + } } else { setDocumentLinks(_data, realParent); } @@ -918,7 +917,8 @@ void Document::draw( .highlight = highlightRequest ? &*highlightRequest : nullptr, }); } - if (_parent->data()->media() && _parent->data()->media()->ttlSeconds()) { + if ((_parent->data()->media() && _parent->data()->media()->ttlSeconds()) + && _openl) { const auto &fg = context.outbg ? st::historyFileOutIconFg : st::historyFileInIconFg; @@ -1739,4 +1739,23 @@ bool DrawThumbnailAsSongCover( return true; } +rpl::producer<> TTLVoiceStops(FullMsgId fullId) { + return rpl::merge( + ::Media::Player::instance()->updatedNotifier( + ) | rpl::filter([=](::Media::Player::TrackState state) { + using State = ::Media::Player::State; + const auto badState = state.state == State::Stopped + || state.state == State::StoppedAtEnd + || state.state == State::StoppedAtError + || state.state == State::StoppedAtStart; + return (state.id.contextId() != fullId) && !badState; + }) | rpl::to_empty, + ::Media::Player::instance()->tracksFinished( + ) | rpl::filter([=](AudioMsgId::Type type) { + return (type == AudioMsgId::Type::Voice); + }) | rpl::to_empty, + ::Media::Player::instance()->stops(AudioMsgId::Type::Voice) + ); +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.h b/Telegram/SourceFiles/history/view/media/history_view_document.h index 5fa8dc1da..3d29651c4 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.h +++ b/Telegram/SourceFiles/history/view/media/history_view_document.h @@ -181,4 +181,6 @@ bool DrawThumbnailAsSongCover( const QRect &rect, bool selected = false); +rpl::producer<> TTLVoiceStops(FullMsgId fullId); + } // namespace HistoryView From 2a81a617e143ee8cb8c414f801cfe3f50fe2fdae Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 9 Jan 2024 16:01:58 +0300 Subject: [PATCH 35/73] Improved loop animation in voice messages with ttl. --- .../view/media/history_view_document.cpp | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 2dc91de74..819c25923 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -99,6 +99,7 @@ void DrawCornerBadgeTTL( struct State final { std::unique_ptr<Lottie::Icon> start; std::unique_ptr<Lottie::Icon> idle; + bool started = false; }; const auto iconSize = Size(std::min( st::historyFileInPause.width(), @@ -110,36 +111,37 @@ void DrawCornerBadgeTTL( .sizeOverride = iconSize, }); - const auto animateSingle = [=]( - not_null<Lottie::Icon*> icon, - Fn<void()> next) { - auto callback = [=] { - update(); - if (icon->frameIndex() == icon->framesCount()) { - next(); - } - }; - icon->animate(std::move(callback), 0, icon->framesCount()); - }; - const auto animate = [=](auto reanimate) -> void { - animateSingle(state->idle.get(), [=] { reanimate(reanimate); }); - }; - animateSingle( - state->start.get(), - [=] { - state->idle = Lottie::MakeIcon({ - .name = u"voice_ttl_idle"_q, - .color = &st::historyFileInIconFg, - .sizeOverride = iconSize, - }); - animate(animate); - }); const auto weak = std::weak_ptr(lifetime); return [=](QPainter &p, QRect r, QColor c) { if (weak.expired()) { return; } - (state->idle ? state->idle : state->start)->paintInCenter(p, r, c); + { + const auto &icon = state->idle; + if (icon) { + icon->paintInCenter(p, r, c); + if (!icon->animating()) { + icon->animate(update, 0, icon->framesCount()); + } + return; + } + } + { + const auto &icon = state->start; + icon->paintInCenter(p, r, c); + if (!icon->animating()) { + if (!state->started) { + icon->animate(update, 0, icon->framesCount()); + state->started = true; + } else { + state->idle = Lottie::MakeIcon({ + .name = u"voice_ttl_idle"_q, + .color = &st::historyFileInIconFg, + .sizeOverride = iconSize, + }); + } + } + } }; } From 53e95a7f7491c597e5df6ea311e8dffcee3d01bb Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 9 Jan 2024 17:06:37 +0300 Subject: [PATCH 36/73] Fixed display of last frame of voice messages in media viewer with ttl. --- .../chat_helpers/ttl_media_layer_widget.cpp | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp index 91403a2c2..baf5c1be6 100644 --- a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp @@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/chat/chat_theme.h" #include "ui/effects/path_shift_gradient.h" #include "ui/painter.h" +#include "ui/rect.h" #include "ui/text/text_utilities.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" @@ -96,6 +97,11 @@ private: std::unique_ptr<HistoryView::Element> _element; rpl::lifetime _elementLifetime; + struct { + QImage frame; + bool use = false; + } _last; + rpl::event_stream<> _closeRequests; }; @@ -200,7 +206,10 @@ PreviewWrap::PreviewWrap( HistoryView::TTLVoiceStops( item->fullId() - ) | rpl::start_with_next(closeCallback, lifetime()); + ) | rpl::start_with_next([=] { + _last.use = true; + closeCallback(); + }, lifetime()); } QRect PreviewWrap::elementRect() const { @@ -225,20 +234,32 @@ void PreviewWrap::paintEvent(QPaintEvent *e) { return; } - auto p = Painter(this); + auto p = QPainter(this); const auto r = rect(); - auto context = _theme->preparePaintContext( - _style.get(), - r, - e->rect(), - !window()->isActiveWindow()); - context.outbg = _element->hasOutLayout(); - + if (!_last.use) { + const auto size = _element->currentSize(); + auto result = QImage( + size * style::DevicePixelRatio(), + QImage::Format_ARGB32_Premultiplied); + result.fill(Qt::transparent); + result.setDevicePixelRatio(style::DevicePixelRatio()); + { + auto q = Painter(&result); + auto context = _theme->preparePaintContext( + _style.get(), + Rect(size), + Rect(size), + !window()->isActiveWindow()); + context.outbg = _element->hasOutLayout(); + _element->draw(q, context); + } + _last.frame = std::move(result); + } p.translate( (r.width() - _element->width()) / 2, (r.height() - _element->height()) / 2); - _element->draw(p, context); + p.drawImage(0, 0, _last.frame); } } // namespace From c43dfecec60277e7f05dca62c971c91ad7a881a7 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 9 Jan 2024 17:25:08 +0300 Subject: [PATCH 37/73] Excluded media with ttl from shared media. --- Telegram/SourceFiles/data/data_media_types.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index e9c4dd66e..fb6560e51 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -902,7 +902,7 @@ bool MediaFile::uploading() const { Storage::SharedMediaTypesMask MediaFile::sharedMediaTypes() const { using Type = Storage::SharedMediaType; - if (_document->sticker()) { + if (_document->sticker() || ttlSeconds()) { return {}; } else if (_document->isVideoMessage()) { return Storage::SharedMediaTypesMask{} From 6516c7aef3d4ba6761c8894d59ff55b1e7ff4d59 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 9 Jan 2024 19:52:43 +0300 Subject: [PATCH 38/73] Fixed display of ttl badges from voice messages with chat themes. --- .../view/media/history_view_document.cpp | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 819c25923..1ea9d6fb9 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -45,28 +45,25 @@ namespace { constexpr auto kAudioVoiceMsgUpdateView = crl::time(100); -void DrawCornerBadgeTTL( - QPainter &p, - const style::color &bg, - const style::color &fg, - const QRect &circleRect) { - p.save(); - const auto partRect = QRectF( - rect::right(circleRect) +[[nodiscard]] QRect TTLRectFromInner(const QRect &inner) { + return QRect( + rect::right(inner) - st::dialogsTTLBadgeSize - + rect::m::sum::h(st::dialogsTTLBadgeInnerMargins), - rect::bottom(circleRect) + + rect::m::sum::h(st::dialogsTTLBadgeInnerMargins) + - st::dialogsTTLBadgeSkip.x(), + rect::bottom(inner) - st::dialogsTTLBadgeSize - + rect::m::sum::v(st::dialogsTTLBadgeInnerMargins), + + rect::m::sum::v(st::dialogsTTLBadgeInnerMargins) + - st::dialogsTTLBadgeSkip.y(), st::dialogsTTLBadgeSize, st::dialogsTTLBadgeSize); +} +void DrawCornerBadgeTTL(QPainter &p, const QColor &fg, const QRect &ttlRect) { + p.save(); auto hq = PainterHighQualityEnabler(p); - p.setPen(Qt::NoPen); - p.setBrush(bg); - p.drawEllipse(partRect); - const auto innerRect = partRect - st::dialogsTTLBadgeInnerMargins; + const auto innerRect = QRectF(ttlRect - st::dialogsTTLBadgeInnerMargins); const auto ttlText = u"1"_q; p.setFont(st::dialogsScamFont); @@ -716,6 +713,11 @@ void Document::draw( } else { p.setPen(Qt::NoPen); + const auto hasTtlBadge = _parent->data()->media() + && _parent->data()->media()->ttlSeconds() + && _openl; + const auto ttlRect = hasTtlBadge ? TTLRectFromInner(inner) : QRect(); + const auto coverDrawn = _data->isSongWithCover() && DrawThumbnailAsSongCover( p, @@ -740,9 +742,12 @@ void Document::draw( } } } else { - PainterHighQualityEnabler hq(p); + auto hq = PainterHighQualityEnabler(p); p.setBrush(stm->msgFileBg); p.drawEllipse(inner); + if (hasTtlBadge) { + p.drawEllipse(ttlRect); + } } } @@ -791,6 +796,9 @@ void Document::draw( QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); _animation->radial.draw(q, rinner, st::msgFileRadialLine, stm->historyFileRadialFg); } + if (hasTtlBadge) { + DrawCornerBadgeTTL(q, stm->historyFileRadialFg->c, ttlRect); + } }; if (_data->isSongWithCover() || !usesBubblePattern(context)) { paintContent(p); @@ -799,7 +807,7 @@ void Document::draw( p, context.viewport, context.bubblesPattern->pixmap, - inner, + hasTtlBadge ? inner.united(ttlRect) : inner, paintContent, _iconCache); } @@ -919,13 +927,6 @@ void Document::draw( .highlight = highlightRequest ? &*highlightRequest : nullptr, }); } - if ((_parent->data()->media() && _parent->data()->media()->ttlSeconds()) - && _openl) { - const auto &fg = context.outbg - ? st::historyFileOutIconFg - : st::historyFileInIconFg; - DrawCornerBadgeTTL(p, stm->msgFileBg, fg, inner); - } } Ui::BubbleRounding Document::thumbRounding( From a1369aaad0294a791a0c382c251c1b09e1220f47 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 9 Jan 2024 20:32:18 +0300 Subject: [PATCH 39/73] Added references to structured bindings since Apple clang supports them. --- Telegram/SourceFiles/boxes/auto_download_box.cpp | 6 +++--- Telegram/SourceFiles/boxes/connection_box.cpp | 2 +- Telegram/SourceFiles/boxes/language_box.cpp | 2 +- Telegram/SourceFiles/boxes/share_box.cpp | 2 +- Telegram/SourceFiles/calls/group/calls_group_call.cpp | 2 +- .../SourceFiles/chat_helpers/emoji_sets_manager.cpp | 2 +- Telegram/SourceFiles/core/core_cloud_password.cpp | 2 +- Telegram/SourceFiles/core/shortcuts.cpp | 4 ++-- Telegram/SourceFiles/data/data_changes.cpp | 2 +- Telegram/SourceFiles/data/data_group_call.cpp | 4 ++-- Telegram/SourceFiles/data/data_histories.cpp | 6 +++--- Telegram/SourceFiles/data/data_session.cpp | 8 ++++---- Telegram/SourceFiles/data/data_stories.cpp | 2 +- Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp | 6 +++--- Telegram/SourceFiles/editor/editor_crop.cpp | 4 ++-- Telegram/SourceFiles/export/export_api_wrap.cpp | 2 +- .../SourceFiles/export/output/export_output_html.cpp | 6 +++--- Telegram/SourceFiles/history/history.cpp | 2 +- Telegram/SourceFiles/history/history_inner_widget.cpp | 4 ++-- .../history/view/history_view_list_widget.cpp | 6 +++--- .../history/view/media/history_view_poll.cpp | 2 +- Telegram/SourceFiles/info/media/info_media_common.cpp | 2 +- .../media/view/media_view_overlay_widget.cpp | 6 +++--- Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp | 2 +- .../SourceFiles/passport/passport_form_controller.cpp | 10 +++++----- .../passport/passport_panel_edit_document.cpp | 2 +- .../SourceFiles/storage/download_manager_mtproto.cpp | 4 ++-- Telegram/SourceFiles/storage/file_upload.cpp | 4 ++-- Telegram/SourceFiles/ui/boxes/single_choice_box.cpp | 2 +- .../ui/chat/attach/attach_album_thumbnail.cpp | 2 +- Telegram/SourceFiles/ui/chat/message_bar.cpp | 2 +- Telegram/SourceFiles/window/notifications_manager.cpp | 2 +- .../SourceFiles/window/window_session_controller.cpp | 2 +- 33 files changed, 58 insertions(+), 58 deletions(-) diff --git a/Telegram/SourceFiles/boxes/auto_download_box.cpp b/Telegram/SourceFiles/boxes/auto_download_box.cpp index ae42f3cc8..3617a9eb6 100644 --- a/Telegram/SourceFiles/boxes/auto_download_box.cpp +++ b/Telegram/SourceFiles/boxes/auto_download_box.cpp @@ -162,7 +162,7 @@ void AutoDownloadBox::setupContent() { *downloadValues, *autoPlayValues); auto allowMore = values | ranges::views::filter([&](Pair pair) { - const auto [type, enabled] = pair; + const auto &[type, enabled] = pair; const auto value = enabled ? limitByType(type) : 0; const auto old = settings->bytesLimit(_source, type); return (old < value); @@ -170,7 +170,7 @@ void AutoDownloadBox::setupContent() { return pair.first; }); const auto less = ranges::any_of(*autoPlayValues, [&](Pair pair) { - const auto [type, enabled] = pair; + const auto &[type, enabled] = pair; const auto value = enabled ? limitByType(type) : 0; return value < settings->bytesLimit(_source, type); }); @@ -179,7 +179,7 @@ void AutoDownloadBox::setupContent() { allowMore.end()); const auto changed = ranges::any_of(values, [&](Pair pair) { - const auto [type, enabled] = pair; + const auto &[type, enabled] = pair; const auto value = enabled ? limitByType(type) : 0; return value != settings->bytesLimit(_source, type); }); diff --git a/Telegram/SourceFiles/boxes/connection_box.cpp b/Telegram/SourceFiles/boxes/connection_box.cpp index 3bdaa932d..4403f56fa 100644 --- a/Telegram/SourceFiles/boxes/connection_box.cpp +++ b/Telegram/SourceFiles/boxes/connection_box.cpp @@ -748,7 +748,7 @@ void ProxiesBox::applyView(View &&view) { const auto wrap = _wrap ? _wrap.data() : _initialWrap.data(); - const auto [i, ok] = _rows.emplace(id, nullptr); + const auto &[i, ok] = _rows.emplace(id, nullptr); i->second.reset(wrap->insert( 0, object_ptr<ProxyRow>( diff --git a/Telegram/SourceFiles/boxes/language_box.cpp b/Telegram/SourceFiles/boxes/language_box.cpp index ab709a87d..aa69a6fee 100644 --- a/Telegram/SourceFiles/boxes/language_box.cpp +++ b/Telegram/SourceFiles/boxes/language_box.cpp @@ -1121,7 +1121,7 @@ void LanguageBox::prepare() { using namespace rpl::mappers; - const auto [recent, official] = PrepareLists(); + const auto &[recent, official] = PrepareLists(); const auto inner = setInnerWidget( object_ptr<Content>(this, recent, official), st::boxScroll, diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index d1b3dbb37..007355317 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -882,7 +882,7 @@ auto ShareBox::Inner::getChat(not_null<Dialogs::Row*> row) row->attached = i->second.get(); return i->second.get(); } - const auto [i, ok] = _dataMap.emplace( + const auto &[i, ok] = _dataMap.emplace( peer, std::make_unique<Chat>(peer, _st.item, [=] { repaintChat(peer); })); updateChatName(i->second.get()); diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.cpp b/Telegram/SourceFiles/calls/group/calls_group_call.cpp index 49dd3db91..5ec38443d 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -3013,7 +3013,7 @@ void GroupCall::checkLastSpoke() { const auto now = crl::now(); auto list = base::take(_lastSpoke); for (auto i = list.begin(); i != list.end();) { - const auto [ssrc, when] = *i; + const auto &[ssrc, when] = *i; if (when.anything + kKeepInListFor >= now) { hasRecent = true; ++i; diff --git a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp index 7c6ae96c8..fed24fc5b 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp @@ -247,7 +247,7 @@ void Row::paintPreview(QPainter &p) const { const auto width = st::manageEmojiPreviewWidth; const auto height = st::manageEmojiPreviewWidth; auto &&preview = ranges::views::zip(_preview, ranges::views::ints(0, int(_preview.size()))); - for (const auto [pixmap, index] : preview) { + for (const auto &[pixmap, index] : preview) { const auto row = (index / 2); const auto column = (index % 2); const auto left = x + (column ? width - st::manageEmojiPreview : 0); diff --git a/Telegram/SourceFiles/core/core_cloud_password.cpp b/Telegram/SourceFiles/core/core_cloud_password.cpp index 99b5d589e..3a65f24d5 100644 --- a/Telegram/SourceFiles/core/core_cloud_password.cpp +++ b/Telegram/SourceFiles/core/core_cloud_password.cpp @@ -128,7 +128,7 @@ CloudPasswordResult ComputeCheck( } }; - const auto [a, AForHash, u] = GenerateAndCheckRandom(); + const auto &[a, AForHash, u] = GenerateAndCheckRandom(); const auto g_b = BigNum::ModSub(B, kg_x, p, context); if (!MTP::IsGoodModExpFirst(g_b, p)) { LOG(("API Error: Bad g_b in cloud password check!")); diff --git a/Telegram/SourceFiles/core/shortcuts.cpp b/Telegram/SourceFiles/core/shortcuts.cpp index 2d10ad484..ad4a79eb7 100644 --- a/Telegram/SourceFiles/core/shortcuts.cpp +++ b/Telegram/SourceFiles/core/shortcuts.cpp @@ -402,7 +402,7 @@ void Manager::fillDefaults() { kShowFolder, ranges::views::ints(1, ranges::unreachable)); - for (const auto [command, index] : folders) { + for (const auto &[command, index] : folders) { set(u"%1+%2"_q.arg(ctrl).arg(index), command); } @@ -410,7 +410,7 @@ void Manager::fillDefaults() { kShowAccount, ranges::views::ints(1, ranges::unreachable)); - for (const auto [command, index] : accounts) { + for (const auto &[command, index] : accounts) { set(u"%1+shift+%2"_q.arg(ctrl).arg(index), command); } diff --git a/Telegram/SourceFiles/data/data_changes.cpp b/Telegram/SourceFiles/data/data_changes.cpp index f20041565..773c50d5d 100644 --- a/Telegram/SourceFiles/data/data_changes.cpp +++ b/Telegram/SourceFiles/data/data_changes.cpp @@ -56,7 +56,7 @@ rpl::producer<UpdateType> Changes::Manager<DataType, UpdateType>::updates( Flags flags) const { return _stream.events( ) | rpl::filter([=](const UpdateType &update) { - const auto [updateData, updateFlags] = update; + const auto &[updateData, updateFlags] = update; return (updateData == data) && (updateFlags & flags); }); } diff --git a/Telegram/SourceFiles/data/data_group_call.cpp b/Telegram/SourceFiles/data/data_group_call.cpp index 0567477c4..72b4d387f 100644 --- a/Telegram/SourceFiles/data/data_group_call.cpp +++ b/Telegram/SourceFiles/data/data_group_call.cpp @@ -847,7 +847,7 @@ void GroupCall::requestUnknownParticipants() { auto result = base::flat_map<uint32, LastSpokeTimes>(); result.reserve(kRequestPerPage); while (result.size() < kRequestPerPage) { - const auto [ssrc, when] = _unknownSpokenSsrcs.back(); + const auto &[ssrc, when] = _unknownSpokenSsrcs.back(); result.emplace(ssrc, when); _unknownSpokenSsrcs.erase(_unknownSpokenSsrcs.end() - 1); } @@ -863,7 +863,7 @@ void GroupCall::requestUnknownParticipants() { result.reserve(available); while (result.size() < available) { const auto &back = _unknownSpokenPeerIds.back(); - const auto [participantPeerId, when] = back; + const auto &[participantPeerId, when] = back; result.emplace(participantPeerId, when); _unknownSpokenPeerIds.erase(_unknownSpokenPeerIds.end() - 1); } diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index dd5b435ee..b171cf0f4 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -123,7 +123,7 @@ not_null<History*> Histories::findOrCreate(PeerId peerId) { if (const auto result = find(peerId)) { return result; } - const auto [i, ok] = _map.emplace( + const auto &[i, ok] = _map.emplace( peerId, std::make_unique<History>(&owner(), peerId)); return i->second.get(); @@ -355,7 +355,7 @@ void Histories::requestDialogEntry( return; } - const auto [j, ok] = _dialogRequestsPending.try_emplace(history); + const auto &[j, ok] = _dialogRequestsPending.try_emplace(history); if (callback) { j->second.push_back(std::move(callback)); } @@ -1130,7 +1130,7 @@ void Histories::finishSentRequest( if (state->postponedRequestEntry && !postponeEntryRequest(*state)) { const auto i = _dialogRequests.find(history); Assert(i != end(_dialogRequests)); - const auto [j, ok] = _dialogRequestsPending.emplace( + const auto &[j, ok] = _dialogRequestsPending.emplace( history, std::move(i->second)); Assert(ok); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 6001a46c2..de0a3c62d 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1097,7 +1097,7 @@ void Session::watchForOffline(not_null<UserData*> user, TimeId now) { return; } const auto till = user->onlineTill; - const auto [i, ok] = _watchingForOffline.emplace(user, till); + const auto &[i, ok] = _watchingForOffline.emplace(user, till); if (!ok) { if (i->second == till) { return; @@ -1626,7 +1626,7 @@ HistoryItem *Session::changeMessageId(PeerId peerId, MsgId wasId, MsgId nowId) { } const auto item = i->second; list->erase(i); - const auto [j, ok] = list->emplace(nowId, item); + const auto &[j, ok] = list->emplace(nowId, item); if (!peerIsChannel(peerId)) { if (IsServerMsgId(wasId)) { @@ -1789,7 +1789,7 @@ void Session::registerHighlightProcess( not_null<HistoryItem*> item) { Expects(item->inHighlightProcess()); - const auto [i, ok] = _highlightings.emplace(processId, item); + const auto &[i, ok] = _highlightings.emplace(processId, item); Ensures(ok); } @@ -4208,7 +4208,7 @@ not_null<Folder*> Session::folder(FolderId id) { if (const auto result = folderLoaded(id)) { return result; } - const auto [it, ok] = _folders.emplace( + const auto &[it, ok] = _folders.emplace( id, std::make_unique<Folder>(this, id)); return it->second.get(); diff --git a/Telegram/SourceFiles/data/data_stories.cpp b/Telegram/SourceFiles/data/data_stories.cpp index abf9227fd..a35279be4 100644 --- a/Telegram/SourceFiles/data/data_stories.cpp +++ b/Telegram/SourceFiles/data/data_stories.cpp @@ -234,7 +234,7 @@ Story *Stories::applySingle(PeerId peerId, const MTPstoryItem &story) { void Stories::requestPeerStories( not_null<PeerData*> peer, Fn<void()> done) { - const auto [i, ok] = _requestingPeerStories.emplace(peer); + const auto &[i, ok] = _requestingPeerStories.emplace(peer); if (done) { i->second.push_back(std::move(done)); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index d7d17a37c..05e54ec6b 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -2458,7 +2458,7 @@ void InnerWidget::appendToFiltered(Key key) { } auto row = std::make_unique<Row>(key, 0, 0); row->recountHeight(_narrowRatio); - const auto [i, ok] = _filterResultsGlobal.emplace(key, std::move(row)); + const auto &[i, ok] = _filterResultsGlobal.emplace(key, std::move(row)); const auto height = filteredHeight(); _filterResults.emplace_back(i->second.get()); _filterResults.back().top = height; @@ -3913,7 +3913,7 @@ void InnerWidget::setupShortcuts() { auto &&folders = ranges::views::zip( Shortcuts::kShowFolder, ranges::views::ints(0, ranges::unreachable)); - for (const auto [command, index] : folders) { + for (const auto &[command, index] : folders) { const auto select = (command == Command::ShowFolderLast) ? (filtersCount - 1) : std::clamp(index, 0, filtersCount - 1); @@ -3940,7 +3940,7 @@ void InnerWidget::setupShortcuts() { auto &&pinned = ranges::views::zip( kPinned, ranges::views::ints(0, ranges::unreachable)); - for (const auto [command, index] : pinned) { + for (const auto &[command, index] : pinned) { request->check(command) && request->handle([=, index = index] { const auto list = (_filterId ? session().data().chatsFilters().chatsList(_filterId) diff --git a/Telegram/SourceFiles/editor/editor_crop.cpp b/Telegram/SourceFiles/editor/editor_crop.cpp index 78a91aa6a..54f8369c2 100644 --- a/Telegram/SourceFiles/editor/editor_crop.cpp +++ b/Telegram/SourceFiles/editor/editor_crop.cpp @@ -212,8 +212,8 @@ void Crop::computeDownState(const QPoint &p) { const auto edge = mouseState(p); const auto &inner = _innerRect; const auto &crop = _cropPaint; - const auto [iLeft, iTop, iRight, iBottom] = RectEdges(inner); - const auto [cLeft, cTop, cRight, cBottom] = RectEdges(crop); + const auto &[iLeft, iTop, iRight, iBottom] = RectEdges(inner); + const auto &[cLeft, cTop, cRight, cBottom] = RectEdges(crop); _down = InfoAtDown{ .rect = crop, .edge = edge, diff --git a/Telegram/SourceFiles/export/export_api_wrap.cpp b/Telegram/SourceFiles/export/export_api_wrap.cpp index 25fe29a71..b23329c03 100644 --- a/Telegram/SourceFiles/export/export_api_wrap.cpp +++ b/Telegram/SourceFiles/export/export_api_wrap.cpp @@ -1553,7 +1553,7 @@ void ApiWrap::appendChatsSlice( continue; } } - const auto [i, ok] = process.indexByPeer.emplace( + const auto &[i, ok] = process.indexByPeer.emplace( info.peerId, nextIndex); if (ok) { diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp index 3f0b03eaf..c543de8a5 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.cpp +++ b/Telegram/SourceFiles/export/output/export_output_html.cpp @@ -1563,7 +1563,7 @@ QByteArray HtmlWriter::Wrap::pushStickerMedia( const QString &basePath) { using namespace Data; - const auto [thumb, size] = WriteImageThumb( + const auto &[thumb, size] = WriteImageThumb( basePath, data.file.relativePath, CalculateThumbSize( @@ -1730,7 +1730,7 @@ QByteArray HtmlWriter::Wrap::pushPhotoMedia( const QString &basePath) { using namespace Data; - const auto [thumb, size] = WriteImageThumb( + const auto &[thumb, size] = WriteImageThumb( basePath, data.image.file.relativePath, CalculateThumbSize( @@ -2790,7 +2790,7 @@ Result HtmlWriter::writeDialogSlice(const Data::MessagesSlice &data) { _settings.path, FormatDateText(date))); } - const auto [info, content] = _chat->pushMessage( + const auto &[info, content] = _chat->pushMessage( message, previous, _dialog, diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index bdc0d659c..f5a9765c0 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -465,7 +465,7 @@ not_null<HistoryItem*> History::insertItem( std::unique_ptr<HistoryItem> item) { Expects(item != nullptr); - const auto [i, ok] = _messages.insert(std::move(item)); + const auto &[i, ok] = _messages.insert(std::move(item)); const auto result = i->get(); owner().registerMessage(result); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index c824976cf..9cf3ab373 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1992,7 +1992,7 @@ void HistoryInner::mouseActionFinish( && !_selected.empty() && _selected.cbegin()->second != FullSelection && !hasCopyRestriction(_selected.cbegin()->first)) { - const auto [item, selection] = *_selected.cbegin(); + const auto &[item, selection] = *_selected.cbegin(); if (const auto view = viewByItem(item)) { TextUtilities::SetClipboardText( view->selectedText(selection), @@ -2925,7 +2925,7 @@ TextForMimeData HistoryInner::getSelectedText() const { return TextForMimeData(); } if (selected.cbegin()->second != FullSelection) { - const auto [item, selection] = *selected.cbegin(); + const auto &[item, selection] = *selected.cbegin(); if (const auto view = viewByItem(item)) { return view->selectedText(selection); } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 984cc0e79..6dcc3497f 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -901,7 +901,7 @@ not_null<Element*> ListWidget::enforceViewForItem( return j->second.get(); } } - const auto [i, ok] = _views.emplace( + const auto &[i, ok] = _views.emplace( item, item->createView(this)); return i->second.get(); @@ -1094,7 +1094,7 @@ void ListWidget::repaintScrollDateCallback() { auto ListWidget::collectSelectedItems() const -> SelectedItems { auto transformation = [&](const auto &item) { - const auto [itemId, selection] = item; + const auto &[itemId, selection] = item; auto result = SelectedItem(itemId); result.canDelete = selection.canDelete; result.canForward = selection.canForward; @@ -3766,7 +3766,7 @@ void ListWidget::refreshItem(not_null<const Element*> view) { } return nullptr; }(); - const auto [i, ok] = _views.emplace( + const auto &[i, ok] = _views.emplace( item, item->createView(this, was.get())); const auto now = i->second.get(); diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp index c08d8fde5..7e96e068f 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp @@ -761,7 +761,7 @@ void Poll::draw(Painter &p, const PaintContext &context) const { auto &&answers = ranges::views::zip( _answers, ranges::views::ints(0, int(_answers.size()))); - for (const auto [answer, index] : answers) { + for (const auto &[answer, index] : answers) { const auto animation = _answersAnimation ? &_answersAnimation->data[index] : nullptr; diff --git a/Telegram/SourceFiles/info/media/info_media_common.cpp b/Telegram/SourceFiles/info/media/info_media_common.cpp index fde5dd01b..23fba5eec 100644 --- a/Telegram/SourceFiles/info/media/info_media_common.cpp +++ b/Telegram/SourceFiles/info/media/info_media_common.cpp @@ -39,7 +39,7 @@ bool ChangeItemSelection( return false; }; if (selected.size() < MaxSelectedItems) { - const auto [i, ok] = selected.try_emplace(item, selectionData); + const auto &[i, ok] = selected.try_emplace(item, selectionData); if (ok) { return true; } diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index c533fd805..3bbc98fb9 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -1720,7 +1720,7 @@ bool OverlayWidget::stateAnimationCallback(crl::time now) { now += st::mediaviewShowDuration + st::mediaviewHideDuration; } for (auto i = begin(_animations); i != end(_animations);) { - const auto [state, started] = *i; + const auto &[state, started] = *i; updateOverRect(state); const auto dt = float64(now - started) / st::mediaviewFadeDuration; if (dt >= 1) { @@ -5494,12 +5494,12 @@ void OverlayWidget::preloadData(int delta) { for (auto index = from; index != till + 1; ++index) { auto entity = entityByIndex(index); if (auto photo = std::get_if<not_null<PhotoData*>>(&entity.data)) { - const auto [i, ok] = photos.emplace((*photo)->createMediaView()); + const auto &[i, ok] = photos.emplace((*photo)->createMediaView()); (*i)->wanted(Data::PhotoSize::Small, fileOrigin(entity)); (*photo)->load(fileOrigin(entity), LoadFromCloudOrLocal, true); } else if (auto document = std::get_if<not_null<DocumentData*>>( &entity.data)) { - const auto [i, ok] = documents.emplace( + const auto &[i, ok] = documents.emplace( (*document)->createMediaView()); (*i)->thumbnailWanted(fileOrigin(entity)); if (!(*i)->canBePlayed(entity.item)) { diff --git a/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp b/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp index 676aa047c..850d5c6c1 100644 --- a/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp +++ b/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp @@ -453,7 +453,7 @@ void StartDedicatedLoader( ready(nullptr); }; - const auto [username, postId] = location; + const auto &[username, postId] = location; ResolveChannel(mtp, username, [=, postId = postId]( const MTPInputChannel &channel) { mtp->send( diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index cf9f4c775..684163163 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -1791,7 +1791,7 @@ void FormController::loadFile(File &file) { return; } file.downloadStatus.set(LoadStatus::Status::InProgress, 0); - const auto [j, ok] = _fileLoaders.emplace( + const auto &[j, ok] = _fileLoaders.emplace( key, std::make_unique<mtpFileLoader>( &_controller->session(), @@ -1823,7 +1823,7 @@ void FormController::loadFile(File &file) { } void FormController::fileLoadDone(FileKey key, const QByteArray &bytes) { - if (const auto [value, file] = findFile(key); file != nullptr) { + if (const auto &[value, file] = findFile(key); file != nullptr) { const auto decrypted = DecryptData( bytes::make_span(bytes), file->hash, @@ -1843,7 +1843,7 @@ void FormController::fileLoadDone(FileKey key, const QByteArray &bytes) { } void FormController::fileLoadProgress(FileKey key, int offset) { - if (const auto [value, file] = findFile(key); file != nullptr) { + if (const auto &[value, file] = findFile(key); file != nullptr) { file->downloadStatus.set(LoadStatus::Status::InProgress, offset); if (const auto fileInEdit = findEditFile(key)) { fileInEdit->fields.downloadStatus = file->downloadStatus; @@ -1853,7 +1853,7 @@ void FormController::fileLoadProgress(FileKey key, int offset) { } void FormController::fileLoadFail(FileKey key) { - if (const auto [value, file] = findFile(key); file != nullptr) { + if (const auto &[value, file] = findFile(key); file != nullptr) { file->downloadStatus.set(LoadStatus::Status::Failed); if (const auto fileInEdit = findEditFile(key)) { fileInEdit->fields.downloadStatus = file->downloadStatus; @@ -2591,7 +2591,7 @@ bool FormController::parseForm(const MTPaccount_AuthorizationForm &result) { const auto row = CollectRequestedRow(required); for (const auto &requested : row.values) { const auto type = requested.type; - const auto [i, ok] = _form.values.emplace(type, Value(type)); + const auto &[i, ok] = _form.values.emplace(type, Value(type)); auto &value = i->second; value.translationRequired = requested.translationRequired; value.selfieRequired = requested.selfieRequired; diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp index 9f71e2e3a..c3715e977 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_edit_document.cpp @@ -530,7 +530,7 @@ void PanelEditDocument::createDetailsRow( const auto isoByPhone = Countries::Instance().countryISO2ByPhone( _controller->bot()->session().user()->phone()); - const auto [it, ok] = _details.emplace( + const auto &[it, ok] = _details.emplace( i, container->add(Ui::PanelDetailsRow::Create( container, diff --git a/Telegram/SourceFiles/storage/download_manager_mtproto.cpp b/Telegram/SourceFiles/storage/download_manager_mtproto.cpp index d6752e768..77aae801b 100644 --- a/Telegram/SourceFiles/storage/download_manager_mtproto.cpp +++ b/Telegram/SourceFiles/storage/download_manager_mtproto.cpp @@ -804,8 +804,8 @@ void DownloadMtprotoTask::placeSentRequest( dcId(), requestData.sessionIndex, Storage::kDownloadPartSize); - const auto [i, ok1] = _sentRequests.emplace(requestId, requestData); - const auto [j, ok2] = _requestByOffset.emplace( + const auto &[i, ok1] = _sentRequests.emplace(requestId, requestData); + const auto &[j, ok2] = _requestByOffset.emplace( requestData.offset, requestId); diff --git a/Telegram/SourceFiles/storage/file_upload.cpp b/Telegram/SourceFiles/storage/file_upload.cpp index f2a014f7e..72ebdaafe 100644 --- a/Telegram/SourceFiles/storage/file_upload.cpp +++ b/Telegram/SourceFiles/storage/file_upload.cpp @@ -359,7 +359,7 @@ void Uploader::upload( void Uploader::currentFailed() { auto j = queue.find(uploadingId); if (j != queue.end()) { - const auto [msgId, file] = std::move(*j); + const auto &[msgId, file] = std::move(*j); queue.erase(j); notifyFailed(msgId, file); } @@ -640,7 +640,7 @@ void Uploader::cancelAll() { currentFailed(); } while (!queue.empty()) { - const auto [msgId, file] = std::move(*queue.begin()); + const auto &[msgId, file] = std::move(*queue.begin()); queue.erase(queue.begin()); notifyFailed(msgId, file); } diff --git a/Telegram/SourceFiles/ui/boxes/single_choice_box.cpp b/Telegram/SourceFiles/ui/boxes/single_choice_box.cpp index a75d8a030..2083a0f48 100644 --- a/Telegram/SourceFiles/ui/boxes/single_choice_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/single_choice_box.cpp @@ -29,7 +29,7 @@ void SingleChoiceBox( layout, st::boxOptionListPadding.top() + st::autolockButton.margin.top())); auto &&ints = ranges::views::ints(0, ranges::unreachable); - for (const auto [i, text] : ranges::views::zip(ints, args.options)) { + for (const auto &[i, text] : ranges::views::zip(ints, args.options)) { layout->add( object_ptr<Ui::Radiobutton>( layout, diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp index 3c8f155d6..adf38109b 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp @@ -324,7 +324,7 @@ void AlbumThumbnail::drawSimpleFrame(QPainter &p, QRect to, QSize size) const { const auto Round = [](float64 value) { return int(base::SafeRound(value)); }; - const auto [from, fillBlack] = [&] { + const auto &[from, fillBlack] = [&] { if (previewWidth < width && previewHeight < height) { const auto toWidth = Round(previewWidth * scaleWidth); const auto toHeight = Round(previewHeight * scaleHeight); diff --git a/Telegram/SourceFiles/ui/chat/message_bar.cpp b/Telegram/SourceFiles/ui/chat/message_bar.cpp index 47f7056e4..c3cf6e113 100644 --- a/Telegram/SourceFiles/ui/chat/message_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/message_bar.cpp @@ -20,7 +20,7 @@ namespace Ui { namespace { [[nodiscard]] int SameFirstPartLength(const QString &a, const QString &b) { - const auto [i, j] = ranges::mismatch(a, b); + const auto &[i, j] = ranges::mismatch(a, b); return (i - a.begin()); } diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp index e0dc8d193..9ab93b934 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -309,7 +309,7 @@ System::Timing System::countTiming( void System::registerThread(not_null<Data::Thread*> thread) { if (const auto topic = thread->asTopic()) { - const auto [i, ok] = _watchedTopics.emplace(topic, rpl::lifetime()); + const auto &[i, ok] = _watchedTopics.emplace(topic, rpl::lifetime()); if (ok) { topic->destroyed() | rpl::start_with_next([=] { clearFromTopic(topic); diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index b4be01c6d..cd537957c 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -1243,7 +1243,7 @@ void SessionController::setupShortcuts() { auto &&accounts = ranges::views::zip( Shortcuts::kShowAccount, ranges::views::ints(0, accountsCount)); - for (const auto [command, index] : accounts) { + for (const auto &[command, index] : accounts) { request->check(command) && request->handle([=] { const auto list = app->domain().orderedAccounts(); if (index >= list.size()) { From fa773c3024daf6e90f564e4f0ea865c4d66c352a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 9 Jan 2024 20:42:50 +0300 Subject: [PATCH 40/73] Fixed incorrect seeking of voice messages with transcribe button. --- .../view/media/history_view_document.cpp | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 1ea9d6fb9..32763b683 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -1262,18 +1262,22 @@ TextState Document::textState( void Document::updatePressed(QPoint point) { // LayoutMode should be passed here. if (const auto voice = Get<HistoryDocumentVoice>()) { - if (voice->seeking()) { - const auto thumbed = Get<HistoryDocumentThumbed>(); - const auto &st = thumbed ? st::msgFileThumbLayout : st::msgFileLayout; - const auto nameleft = st.padding.left() + st.thumbSize + st.thumbSkip; - const auto nameright = st.padding.right(); - voice->setSeekingCurrent(std::clamp( - (point.x() - nameleft) - / float64(width() - nameleft - nameright), - 0., - 1.)); - repaint(); + if (!voice->seeking()) { + return; } + const auto thumbed = Get<HistoryDocumentThumbed>(); + const auto &st = thumbed ? st::msgFileThumbLayout : st::msgFileLayout; + const auto nameleft = st.padding.left() + st.thumbSize + st.thumbSkip; + const auto nameright = st.padding.right(); + const auto transcribeWidth = voice->transcribe + ? (st::historyTranscribeSkip + voice->transcribe->size().width()) + : 0; + voice->setSeekingCurrent(std::clamp( + (point.x() - nameleft) + / float64(width() - transcribeWidth - nameleft - nameright), + 0., + 1.)); + repaint(); } } From b017cc07cec56da8d9e7b18dafbb19e2a0bf63a9 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 10 Jan 2024 23:41:01 +0300 Subject: [PATCH 41/73] Removed uppercase from phrase in calls top bar. --- Telegram/SourceFiles/calls/calls_top_bar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/calls/calls_top_bar.cpp b/Telegram/SourceFiles/calls/calls_top_bar.cpp index 17f0008e8..6a3314578 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.cpp +++ b/Telegram/SourceFiles/calls/calls_top_bar.cpp @@ -267,7 +267,7 @@ TopBar::TopBar( ? object_ptr<Ui::LabelSimple>( this, st::callBarLabel, - tr::lng_call_bar_hangup(tr::now).toUpper()) + tr::lng_call_bar_hangup(tr::now)) : object_ptr<Ui::LabelSimple>(nullptr)) , _mute(this, st::callBarMuteToggle) , _info(this) From 40ff71b2cd3360d0d61aa1a602a045f33c3702d6 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 10 Jan 2024 23:58:01 +0300 Subject: [PATCH 42/73] Added delay to button for media replacement in compose control. --- Telegram/SourceFiles/history/history_widget.cpp | 13 ++++++++----- .../controls/history_view_compose_controls.cpp | 14 +++++++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 7cbe283fe..97c586aed 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2600,12 +2600,15 @@ bool HistoryWidget::updateReplaceMediaButton() { return false; } _replaceMedia.create(this, st::historyReplaceMedia); + const auto hideDuration = st::historyReplaceMedia.ripple.hideDuration; _replaceMedia->setClickedCallback([=] { - EditCaptionBox::StartMediaReplace( - controller(), - { _history->peer->id, _editMsgId }, - _field->getTextWithTags(), - crl::guard(_list, [=] { cancelEdit(); })); + base::call_delayed(hideDuration, this, [=] { + EditCaptionBox::StartMediaReplace( + controller(), + { _history->peer->id, _editMsgId }, + _field->getTextWithTags(), + crl::guard(_list, [=] { cancelEdit(); })); + }); }); return true; } diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index b25be58f9..57cff6c0c 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "history/view/controls/history_view_compose_controls.h" +#include "base/call_delayed.h" #include "base/event_filter.h" #include "base/platform/base_platform_info.h" #include "base/qt_signal_producer.h" @@ -2692,12 +2693,15 @@ bool ComposeControls::updateReplaceMediaButton() { _replaceMedia = std::make_unique<Ui::IconButton>( _wrap.get(), st::historyReplaceMedia); + const auto hideDuration = st::historyReplaceMedia.ripple.hideDuration; _replaceMedia->setClickedCallback([=] { - EditCaptionBox::StartMediaReplace( - _regularWindow, - _editingId, - _field->getTextWithTags(), - crl::guard(_wrap.get(), [=] { cancelEditMessage(); })); + base::call_delayed(hideDuration, _wrap.get(), [=] { + EditCaptionBox::StartMediaReplace( + _regularWindow, + _editingId, + _field->getTextWithTags(), + crl::guard(_wrap.get(), [=] { cancelEditMessage(); })); + }); }); return true; } From 21dcb7b13c634044c4e9f325d31338a8e13e2938 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 03:49:09 +0300 Subject: [PATCH 43/73] Added initial ability to play video messages with ttl. --- .../Resources/art/ttl/video_message_icon.svg | 4 + Telegram/Resources/icons/chat/audio_once.png | Bin 0 -> 776 bytes .../Resources/icons/chat/audio_once@2x.png | Bin 0 -> 1426 bytes .../Resources/icons/chat/audio_once@3x.png | Bin 0 -> 2115 bytes Telegram/Resources/qrc/telegram/telegram.qrc | 1 + .../history/history_item_helpers.cpp | 4 - .../history/history_item_helpers.h | 1 - .../view/media/history_view_document.cpp | 2 +- .../history/view/media/history_view_gif.cpp | 124 +++++++++++++++--- .../history/view/media/history_view_gif.h | 7 + Telegram/SourceFiles/ui/chat/chat.style | 2 + Telegram/SourceFiles/ui/chat/chat_style.cpp | 4 + Telegram/SourceFiles/ui/chat/chat_style.h | 1 + 13 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 Telegram/Resources/art/ttl/video_message_icon.svg create mode 100644 Telegram/Resources/icons/chat/audio_once.png create mode 100644 Telegram/Resources/icons/chat/audio_once@2x.png create mode 100644 Telegram/Resources/icons/chat/audio_once@3x.png diff --git a/Telegram/Resources/art/ttl/video_message_icon.svg b/Telegram/Resources/art/ttl/video_message_icon.svg new file mode 100644 index 000000000..aeadc8385 --- /dev/null +++ b/Telegram/Resources/art/ttl/video_message_icon.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg baseProfile="tiny" version="1.2" viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg"> +<path d="m27.57 30.79q0.77-0.44 1.14-1.28 4.38-9.86 4.67-24.25 0.03-1.64 1.63-1.54 1.14 0.07 1.9 0.65c14.45 10.9 28.35 31.97 18.06 50.37-9.55 17.08-32.38 15.75-41.59-0.69-5.25-9.37-0.83-23.06 4.26-32.03a2.13 2.12 43.5 0 1 3.64-0.09l5.53 8.68a0.57 0.56-31.3 0 0 0.76 0.18z" fill="#fff"/> +</svg> diff --git a/Telegram/Resources/icons/chat/audio_once.png b/Telegram/Resources/icons/chat/audio_once.png new file mode 100644 index 0000000000000000000000000000000000000000..4d1f93652302cd716fe27732e3c5dbe8aba3f60c GIT binary patch literal 776 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfvL#T#WBP} zaBGNdww9yF)guZ*M~-McViz+@@=z3WQp#AUk)^n(b-@x((T-MEoi)xTEZVy#_zALb z|8I!sXl*TPYF*GF->dY<-C$OEP1@bq^1HA0a$6Tazf+u6{%-DWn|t<~E+_w<GiQ!O zuiNgs?@FwG*3|93Yj@11%X{f17bQa(zIu++&p%sl3tL@VTRZjiQ}?648}7fC?>~NH z;msVU$3;88RQ<hq^Jd?NFJD?Nq!?9JRNU~6m=mGHb}zwzgRR*@YBHmNQ0JMn&F|mm zPxLsVk~8u5@9H-}>#tAsQnhY&DBN=Uc65^K{Hs}Ci*~*#u?i0l|H5(IYx(85^XFfd zcv&JfKY8=b42|bZrUw~~XY!ofwP#Pv+OVTZ6I(d=^?TeF-^}^;=uy*wy7W7oa}qX2 zc&JQ@=U934xdHdW0F40amIS%}=LyO>@o{kipQ`qLV6Di@%QKkfrP>qX9Hc$<)bZo) zHge(|+s-goS64@`zrLhk`hvq-1Q!Kpv|RsHW5<**fBSS+n;r{e>sH~rtG7vit+MSo z!LhtWHN!w+*=5aNf*aquZH?kxd^9QXVUg1cexXhI3UaT$fBhP&H$5^`#`4wo-!H5e z26%AU+uKjn+<x2FsinNU+<gA|LM|qS=P`QU|NQY;_i*8*4A(8Iy_POw{io;W-~Vsh zj1)PpJvVctdfVI<CvpZWOg=fqN9|~mA?xDZ4+|v3b4;Xc?d&FLE-CmRU0Gj${CC2O z2(OlhRx*4t0zY4s?Oqw8CBQM`?6beIu1f`-x+B+ywM}7kXtR%5eYGhqz11o4xYObV zn@{L1&Dfb|Z1?ZiuPC+257R<chjzWH-&N0WVj|~^$r|0WL8;Kw)z4*}Q$iB}r1wNV literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/audio_once@2x.png b/Telegram/Resources/icons/chat/audio_once@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f66cfbbcb64460699be84a0b5fb13782246fb078 GIT binary patch literal 1426 zcmV;D1#S9?P)<h;3K|Lk000e1NJLTq001xm001xu0ssI2*kEqZ00001b5ch_0Itp) z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG{7FPXR9Fe^SXn4`T@*HD4jIZE z$&i#GQs#Lolth{0Lbx;}TqsIOnKFcwF(o%jp$v(VL|hOVE@V!I%rbq?|DU&QpY!f_ zlGlInf9GoLwVt*1bJpHx@3oGK%HQWVGN7%kt)`~-8#6KI(9zL}kB{%@=$M|K-rU^0 zzP|qa{5(HD_w@8+;+3UTRaH$%Nf{j-eRy~P1M#Q1xmhr`y1KfrudlJOu|WR=!<d+u zwY4>I5=8U<{+^haD3}Q;1OP8kRaK>@rzfy7hpJ31t#oj3=<e<g2??Q<kk8J}=H}*( zj*d=GPft!x*4Nj!x3_7Gg@pz5L<3}IW+q&S<~u@UWaQP=6-fgG#I32R!9rjKrANdz zUtL|LeUZhAiVEpo(yWDrg>P?fBqErVmX=~iOY`B|^!4>yTU)_{1cBh><itnGH>#|x zq@xTB3>X<1$>%CW`T6;6Y;17RK+e|IR)~-}#@F=m@xg^al8TFqWx7ZQXliOAyAu-= zX=!QFkqoQ1xA)`YBgf|D<s~*YmI3-T70%p)g9EZyIXOAMHZ^;qva&M5rmn7z4f+Xf zSXfv?Lql+Iu(V*NrlvPHHyk0HE6Tf`9336G?-yIb+1Xhlr>3SRk{+Bu5^;P34y3ra zxbpIHcXxNbMdAqQArrN?x3h5?8XA|EmmF?#a*_=a)4I92EiW&V=$J_i!cb^wX>nIF z9PjV%4Gatzpz!c;5;r0uf`Q<xkeH&PqUYyl;sv3rtBa44IO^=|B#x=6sSI38OACj< ziHvM95PTIK@%8nU^Box(;iDvu0s;aEA)LAl9QoS&`}-MYF%`GIx3{<1+1WEQGl~*I zy#4)s&TDCDNf=&NSC{ZjPfr(`S>x#FXl!IFD=QekM<^pB12+kt+}vE@45%>(p}@dE zp;^}WdxQ`b?_+IkO@|ll74Ahj16{<>P-V!+$H#)OqRQOT(vlc{lMtDd2qHpQ$S>7@ z*gvSKhzQYHp_h-aRFZ(Q1m6=KTttXoOM3Ze=#R^&bC3ue*#!j!B)EtW3U#8gx3?#< zQUw&HCMG6G5{?ftk%$m(-QC??PK%q8n3X3O8XDpx<Km;qBom1UVT=xt)1n1KnMM#w z5)u*;kQ**I+BY%_gAiJUsHiA{P?C_GoJ=B*kB<}iOF%h>oy48ji;Ih2205hR;bG2E zVsXO{g4{ekJ#j8OJ3D+MHL9+zCKm|(1{8!XVwLf+TwGkB<6$HCTJ-#+|3nSLH&P=k z78+!Z)85`5$|%YxLqr2f_Jj=Rzh?C2V`F2rwY4%zo&5ZKlBB-AK6yeb7X!Ye%LFqt zA<CUkp6KYk$pWK){i)Ur`vxDci;Igq9E2Fu>ZB?~p3p!coDihQ*wxi_Wn~4S(EWV# zOv%g3Bby1r)YO!not+{aL|B|AB_$<vFMww28*%<|K{G)Ay~Fi_pLS+uX7YzKH#c8c zSfF1Fi4O`2l0SkF>EYo)ihnNd-Q8VpZ*Njk63z%AT5R0Y(?he_+S>B*@exBQs6a{v z2M5XD88QJ@VSavoXlSUuz8?Q;LPJBv1H+NSqW}c#C$C7f$+&R{8>Wzzl_lV0V`GEU zZ+3R}8;ye?6np6J@88zec6fNmB-Gg0$aYgitEve23+v_Og|Z1hG4QJu4~k5%#Px>@ g=L_^#`hR5L4={7U!d34{WB>pF07*qoM6N<$f-Fvk6951J literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/audio_once@3x.png b/Telegram/Resources/icons/chat/audio_once@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..bce2481c5534a96ce9c1659f2e5b8becf9c2eb20 GIT binary patch literal 2115 zcmV-J2)y@+P)<h;3K|Lk000e1NJLTq002k;002k`0ssI2+K(g<00001b5ch_0Itp) z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?tw}^dRA>e5n@5NhO%Q;0U31Q2 zR?Ha{RLqF7tcnrLC`Lr_Vz>w<P!UngARde;dl17x%&1_-A0vu62h94bnE(I7fqC_M zrl)6SXWX~2?^NAgvAd_bx~gAVTK+G82J&Yh&KXFLiFttn1!~u>-KbHc1`QgND_5>m zsZu3NmVEZ?+4}YCU%h%2lhC->rl+U3Z{L3Q?AeD8AO8IL^M7u?2M->UE?qh<4I<~; zuwlc63m4wMf8Wg(wQtz4VUa5kJ;QeG+U?%G`}gnPs`~nN|Ni}TdW;=A_Mbn$88c=S zDN;m-7H>Zv&%S;8^!mGxoIZWJP@zJunhh8*K+@d1cW>y>p{|&II>R^*=5p@bxie?Z zEL^y-hm7yvzu&!k_tvdjj~_q&_s{S4?c00z?)~xOhbz^N9Xo~(AFd1?KYo1l=+SUc z`lD}Fty=ZWnKN=~75Ln_b93g*>C&Z(x7kk3)~#Eou(FzO-@Y9*Xpj>>${xO`r%#`{ zivRfW<Dx~2*q@>0)vsUw_3PKJ%;{XPU_ofk212&P*RNllg6UkbVnxM@6%F)0hHKQQ zk)56G6k+u=ZQ9fakANskmo9b6`}OPB=FOWqhyyY+pm*rdf&J_hH+b-117*-*{De~s zTfbMYUO`#;#Lvjcm_L91&!0bSx!=Bht5vI(PjX*qef#!hWo!W!aP8W)diCo0qR#<R z=gyt4UcHLMckkYf7%?IToE)SrTC~6`C{}SI6Z<)EW9cAFt5T(k?&u3CvU26hgm#Km zn>KAiSV)d3LU#1%QN^kgCr$)Col?Y>gc>+^#VW#x3Kc3OF!CbA4eI5~m(sBJ@836R z(j-M}A*><Px^d&ik|j%m?V!br7fY*v$BY@1B39L@Q%A-L#0Gv9W4S(j_#h3tc<~}P zV!!knJnomc@3w8*=Fr7Wn>J1AhLJcqjm+e3B6mp%+_PuTWRzg7YSpT3*s#GqZ8-y( z^<XRnHV2xb9x=BV*MPY4hYuf0%KiKIYjAyaPna-)D~n_Z%t`2r*bRx5R~V8?G4FyN zJ$figv~1bZjla3CQl(0J_Uuu(Sxv$*Grb;T&6+g|+pMfCJ^G)KjT<*gnp3Av83;7P zd`>T3ypXIESVQNlo6C`sjNmS3pj56~lO|0v5V#F<zxeXyi?l>(GUP@Vpzp$k3z9#d zj~8*{#*HO5v%+@rBG8N}w}B%^j*ym<oO5p2ym|8!hF*8v$&)8b>`Rv}X*4%<H*enD z@`0Z|eVRUfIu3~&q~r{2U|||=-MY2HuvxQaTB5aU*GlY_D_3e!O#`@ia!dr~7GmUv z!It2|)|Q>=r4f6^Mg<r@e!LfUkg+%nD_gcKD?w(7w7KDoe)Q;(G^|snPC=CS!i~c) zFL`NcNr94*kTJL#Z^pSjnlOwsL$PATq(0o8WixNV3B#PXeSBKpGDd2fFpN`64glvo zqE{IH&1S+d)(6iaWmBq?&AbIC3}eNp)=BNllqn;dsR>uFUcGqn;!fQXhA~DuKw|ub z%%Kz)6h=L=j!&LEA=)Np@*-F2T~nq^@xl%=7RNb8%FI4>*>2RkrAA3BcJt;<Io7IG zE7?pbm>t-)Ygbz(!cpREy9tnF*yYQY<rtSv*-R<enXO<?YBj7`v!=bc77$e>CGxGf zZQC}fD)&7@&6>)pB$zd8mUbF~3`A=fZjd~u)br4xLy9^{Tahs(b(1>jM5*_XAw!g- z=-|PF62S!~?<Z#hIFc`oTqTan=1iK&MYiv*lP6EwtN^IiQyDi?llPNk+~FcAuSjjE z$C~xfV32-O>UDmTc~hrOm4*S2963@WB|vwdK7Du&0k<nxu5|3!F#u&UYSE%a?cA%S zXYby<lTkD+C`my|+o+Nme2#{d(#^`(ty@>=4AES^e7UV2w|>`PJ;TY@nvcxPOnZn+ zIR2EqWcP#y@MfWDZ9;q?i_a@MoIa0}bT49T`~<-ISlh;)7>FbBA_*C}1@R)lw#ov? zOMB(+a!b(=a<^>RqS!_-iQ^8zDz!*Rft){oUa^hBwCnvRwNy81!@);zsn|vxFsc~R zsKB^!<M7EG=u}Helqg}u4}j37O&jMsSUgg<ZruWK366>x+qZ9*b4v9nI2%t29x=&) z$P$L1<S6%~3qMF|{`&Rn(kkFPckYDesG}s^&1)t_63w$`&vx(LT}Kt7-%4C7v4th~ z*s)_F7@A4Qc<X9;2M!!yj?FAg7`%sk{`|Rf`sg7-VARAQ>^L`3rQ&8Q!Cu|9YgfO1 z{mkWHjdTJoHk-{*0z?b3=P5V?ly6#U0L&{<UiVI%IFT}9!GZ-fR=9LiIZ#+x&7C`U z{=KLAqehL=?HQ>Y@0~f*iBq{*Y~8w*cMBdRQdUekTG;u#d~%tCSi6|TWy_X1i_6k5 zC(NPbG5v(2Z{ECt3YWWT)hgwh9IH7hb1H7UPf{`vPJ3jJ_dg}5jo>88moKkM%9S=j z7MD@-C9ZB-S_SO!Pl;Sn-j`5jdf>o;t5>fk>~h_u9{-f^CBQdQjBiD820TyZro)AR t4aSd0Bp&~i@U3$`V*U)|&p-;y!2gyI^B>FjSK$Bv002ovPDHLkV1mRq0BryO literal 0 HcmV?d00001 diff --git a/Telegram/Resources/qrc/telegram/telegram.qrc b/Telegram/Resources/qrc/telegram/telegram.qrc index 57afe3882..ccf1a1d7a 100644 --- a/Telegram/Resources/qrc/telegram/telegram.qrc +++ b/Telegram/Resources/qrc/telegram/telegram.qrc @@ -26,6 +26,7 @@ <file alias="recording/info_audio.svg">../../art/recording/recording_info_audio.svg</file> <file alias="recording/info_video_landscape.svg">../../art/recording/recording_info_video_landscape.svg</file> <file alias="recording/info_video_portrait.svg">../../art/recording/recording_info_video_portrait.svg</file> + <file alias="ttl/video_message_icon.svg">../../art/ttl/video_message_icon.svg</file> <file alias="icons/settings/dino.svg">../../icons/settings/dino.svg</file> <file alias="icons/settings/star.svg">../../icons/settings/star.svg</file> <file alias="icons/settings/starmini.svg">../../icons/settings/starmini.svg</file> diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 4a29e4e93..a249195c9 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -808,7 +808,3 @@ void ClearMediaAsExpired(not_null<HistoryItem*> item) { } } } - -[[nodiscard]] bool IsVoiceOncePlayable(not_null<HistoryItem*> item) { - return !item->out() && item->media()->ttlSeconds(); -} diff --git a/Telegram/SourceFiles/history/history_item_helpers.h b/Telegram/SourceFiles/history/history_item_helpers.h index f96d9c092..c438eccbe 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.h +++ b/Telegram/SourceFiles/history/history_item_helpers.h @@ -158,4 +158,3 @@ ClickHandlerPtr JumpToStoryClickHandler( void ShowTrialTranscribesToast(int left, TimeId until); void ClearMediaAsExpired(not_null<HistoryItem*> item); -[[nodiscard]] bool IsVoiceOncePlayable(not_null<HistoryItem*> item); diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 32763b683..cf5560009 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -425,7 +425,7 @@ void Document::createComponents(bool caption) { _realParent->fullId()); } if (const auto voice = Get<HistoryDocumentVoice>()) { - voice->seekl = !IsVoiceOncePlayable(_parent->data()) + voice->seekl = !_parent->data()->media()->ttlSeconds() ? std::make_shared<VoiceSeekClickHandler>(_data, [](FullMsgId) {}) : nullptr; if (_transcribedRound) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 87a0e00bf..6176bf050 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/view/media_view_playback_progress.h" #include "ui/boxes/confirm_box.h" #include "ui/painter.h" +#include "ui/rect.h" #include "history/history_item_components.h" #include "history/history_item_helpers.h" #include "history/history_item.h" @@ -30,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_cursor_state.h" #include "history/view/history_view_reply.h" #include "history/view/history_view_transcribe_button.h" +#include "history/view/media/history_view_document.h" // TTLVoiceStops #include "history/view/media/history_view_media_common.h" #include "history/view/media/history_view_media_spoiler.h" #include "window/window_session_controller.h" @@ -52,6 +54,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_document_media.h" #include "styles/style_chat.h" +#include <QSvgRenderer> + namespace HistoryView { namespace { @@ -65,6 +69,41 @@ int gifMaxStatusWidth(DocumentData *document) { return result; } +[[nodiscard]] HistoryView::TtlRoundPaintCallback CreateTtlPaintCallback( + Fn<void()> update) { + const auto iconSize = Size(std::min( + st::historyFileInPause.width(), + st::historyFileInPause.height())); + const auto centerMargins = Margins(st::historyFileInPause.width() * 3); + + const auto renderer = std::make_shared<QSvgRenderer>( + u":/gui/ttl/video_message_icon.svg"_q); + + return [=](QPainter &p, QRect r, const PaintContext &context) { + const auto centerRect = r - centerMargins; + const auto &icon = context.imageStyle()->historyVideoMessageTtlIcon; + const auto iconRect = QRect( + rect::right(centerRect) - icon.width() * 0.75, + rect::bottom(centerRect) - icon.height() * 0.75, + icon.width(), + icon.height()); + { + auto hq = PainterHighQualityEnabler(p); + auto path = QPainterPath(); + path.setFillRule(Qt::WindingFill); + path.addEllipse(centerRect); + path.addEllipse(iconRect); + p.fillPath(path, st::shadowFg); + p.fillPath(path, st::shadowFg); + p.fillPath(path, st::shadowFg); + } + + renderer->render(&p, centerRect - Margins(centerRect.width() / 4)); + + icon.paint(p, iconRect.topLeft(), centerRect.width()); + }; +} + } // namespace struct Gif::Streamed { @@ -83,6 +122,12 @@ Gif::Streamed::Streamed( : instance(std::move(shared), std::move(waitingCallback)) { } +[[nodiscard]] bool IsHiddenRoundMessage(not_null<Element*> parent) { + return parent->delegate()->elementContext() != Context::TTLViewer + && parent->data()->media() + && parent->data()->media()->ttlSeconds(); +} + Gif::Gif( not_null<Element*> parent, not_null<HistoryItem*> realParent, @@ -95,18 +140,45 @@ Gif::Gif( : FullStoryId()) , _caption( st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) -, _spoiler(spoiler ? std::make_unique<MediaSpoiler>() : nullptr) +, _spoiler((spoiler || IsHiddenRoundMessage(_parent)) + ? std::make_unique<MediaSpoiler>() + : nullptr) , _downloadSize(Ui::FormatSizeText(_data->size)) { - setDocumentLinks(_data, realParent, [=] { - if (!_data->createMediaView()->canBePlayed(realParent) - || !_data->isAnimation() - || _data->isVideoMessage() - || !CanPlayInline(_data)) { - return false; + auto hasDefaultDocumentLinks = false; + if (_data->isVideoMessage() && _parent->data()->media()->ttlSeconds()) { + if (_spoiler) { + _drawTtl = CreateTtlPaintCallback([=] { repaint(); }); } - playAnimation(false); - return true; - }); + const auto fullId = _realParent->fullId(); + _parent->data()->removeFromSharedMediaIndex(); + setDocumentLinks(_data, realParent, [=] { + auto lifetime = std::make_shared<rpl::lifetime>(); + TTLVoiceStops(fullId) | rpl::start_with_next([=]() mutable { + const auto item = _parent->data(); + if (lifetime) { + base::take(lifetime)->destroy(); + } + if (!item->out()) { + // Destroys this. + ClearMediaAsExpired(item); + } + }, *lifetime); + + return false; + }); + } else { + setDocumentLinks(_data, realParent, [=] { + if (!_data->createMediaView()->canBePlayed(realParent) + || !_data->isAnimation() + || _data->isVideoMessage() + || !CanPlayInline(_data)) { + return false; + } + playAnimation(false); + return true; + }); + } + setStatusSize(Ui::FileStatusSizeReady); if (_spoiler) { @@ -403,7 +475,13 @@ void Gif::draw(Painter &p, const PaintContext &context) const { QRect rthumb(style::rtlrect(usex + paintx, painty, usew, painth, width())); - const auto revealed = (!isRound && _spoiler) + const auto inTTLViewer = _parent->delegate()->elementContext() + == Context::TTLViewer; + const auto revealed = (isRound + && item->media()->ttlSeconds() + && !inTTLViewer) + ? 0 + : (!isRound && _spoiler) ? _spoiler->revealAnimation.value(_spoiler->revealed ? 1. : 0.) : 1.; const auto fullHiddenBySpoiler = (revealed == 0.); @@ -525,10 +603,19 @@ void Gif::draw(Painter &p, const PaintContext &context) const { p.drawImage(rthumb, _thumbCache); } - if (!isRound && revealed < 1.) { + if (revealed < 1.) { p.setOpacity(1. - revealed); - p.drawImage(rthumb.topLeft(), _spoiler->background); - fillImageSpoiler(p, _spoiler.get(), rthumb, context); + if (!isRound) { + p.drawImage(rthumb.topLeft(), _spoiler->background); + fillImageSpoiler(p, _spoiler.get(), rthumb, context); + } else { + auto frame = _spoiler->background; + { + auto q = QPainter(&frame); + fillImageSpoiler(q, _spoiler.get(), rthumb, context); + } + p.drawImage(rthumb.topLeft(), Images::Circle(std::move(frame))); + } p.setOpacity(1.); } if (context.selected()) { @@ -793,6 +880,9 @@ void Gif::draw(Painter &p, const PaintContext &context) const { paintTranscribe(p, usex, fullBottom, false, context); } } + if (_drawTtl) { + _drawTtl(p, rthumb, context); + } } void Gif::paintTranscribe( @@ -1108,7 +1198,9 @@ TextState Gif::textState(QPoint point, StateRequest request) const { } if (QRect(usex + paintx, painty, usew, painth).contains(point)) { ensureDataMediaCreated(); - result.link = (_spoiler && !_spoiler->revealed) + result.link = (isRound && _parent->data()->media()->ttlSeconds()) + ? _openl // Overriden. + : (_spoiler && !_spoiler->revealed) ? _spoiler->link : _data->uploading() ? _cancell @@ -1970,7 +2062,7 @@ bool Gif::needCornerStatusDisplay() const { void Gif::ensureTranscribeButton() const { if (_data->isVideoMessage() - && !IsVoiceOncePlayable(_parent->data()) + && !_parent->data()->media()->ttlSeconds() && (_data->session().premium() || _data->session().api().transcribes().trialsSupport())) { if (!_transcribe) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h index 1d1b30e4a..dad49b351 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.h +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h @@ -40,6 +40,11 @@ namespace HistoryView { class Reply; class TranscribeButton; +using TtlRoundPaintCallback = Fn<void( + QPainter&, + QRect, + const PaintContext &context)>; + class Gif final : public File { public: Gif( @@ -214,6 +219,8 @@ private: void togglePollingStory(bool enabled) const; + TtlRoundPaintCallback _drawTtl; + const not_null<DocumentData*> _data; const FullStoryId _storyId; Ui::Text::String _caption; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index bc54f7366..378393643 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -536,6 +536,8 @@ historyVideoMessageMute: icon {{ "volume_mute", historyFileThumbIconFg }}; historyVideoMessageMuteSelected: icon {{ "volume_mute", historyFileThumbIconFgSelected }}; historyVideoMessageMuteSize: 25px; historyVideoMessageProgressOpacity: 0.72; +historyVideoMessageTtlIcon: icon {{ "chat/audio_once", historyFileThumbIconFg }}; +historyVideoMessageTtlIconSelected: icon {{ "chat/audio_once", historyFileThumbIconFgSelected }}; historyAdminLogEmptyWidth: 260px; historyAdminLogEmptyPadding: margins(10px, 12px, 10px, 12px); diff --git a/Telegram/SourceFiles/ui/chat/chat_style.cpp b/Telegram/SourceFiles/ui/chat/chat_style.cpp index 0fc4840f1..4acf416ba 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_style.cpp @@ -528,6 +528,10 @@ ChatStyle::ChatStyle(rpl::producer<ColorIndicesCompressed> colorIndices) { &MessageImageStyle::historyVideoMessageMute, st::historyVideoMessageMute, st::historyVideoMessageMuteSelected); + make( + &MessageImageStyle::historyVideoMessageTtlIcon, + st::historyVideoMessageTtlIcon, + st::historyVideoMessageTtlIconSelected); make( &MessageImageStyle::historyPageEnlarge, st::historyPageEnlarge, diff --git a/Telegram/SourceFiles/ui/chat/chat_style.h b/Telegram/SourceFiles/ui/chat/chat_style.h index 45a4f3caf..11890a061 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.h +++ b/Telegram/SourceFiles/ui/chat/chat_style.h @@ -118,6 +118,7 @@ struct MessageImageStyle { style::icon historyVideoDownload = { Qt::Uninitialized }; style::icon historyVideoCancel = { Qt::Uninitialized }; style::icon historyVideoMessageMute = { Qt::Uninitialized }; + style::icon historyVideoMessageTtlIcon = { Qt::Uninitialized }; style::icon historyPageEnlarge = { Qt::Uninitialized }; }; From 5ba918d2134d59c27393fc2fe94706351e2e2c6a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 04:00:59 +0300 Subject: [PATCH 44/73] Added support of chat themes to viewer widget for messages with ttl. --- .../chat_helpers/ttl_media_layer_widget.cpp | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp index baf5c1be6..e6a71d509 100644 --- a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp @@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" #include "ui/widgets/tooltip.h" +#include "window/section_widget.h" // Window::ChatThemeValueFromPeer. #include "window/themes/window_theme.h" #include "window/window_session_controller.h" #include "styles/style_chat.h" @@ -81,7 +82,10 @@ bool PreviewDelegate::elementIsChatWide() { class PreviewWrap final : public Ui::RpWidget { public: - PreviewWrap(not_null<Ui::RpWidget*> parent, not_null<HistoryItem*> item); + PreviewWrap( + not_null<Ui::RpWidget*> parent, + not_null<HistoryItem*> item, + rpl::producer<std::shared_ptr<Ui::ChatTheme>> theme); ~PreviewWrap(); [[nodiscard]] rpl::producer<> closeRequests() const; @@ -91,9 +95,9 @@ private: [[nodiscard]] QRect elementRect() const; const not_null<HistoryItem*> _item; - const std::unique_ptr<Ui::ChatTheme> _theme; const std::unique_ptr<Ui::ChatStyle> _style; const std::unique_ptr<PreviewDelegate> _delegate; + std::shared_ptr<Ui::ChatTheme> _theme; std::unique_ptr<HistoryView::Element> _element; rpl::lifetime _elementLifetime; @@ -108,17 +112,23 @@ private: PreviewWrap::PreviewWrap( not_null<Ui::RpWidget*> parent, - not_null<HistoryItem*> item) + not_null<HistoryItem*> item, + rpl::producer<std::shared_ptr<Ui::ChatTheme>> theme) : RpWidget(parent) , _item(item) -, _theme(Window::Theme::DefaultChatThemeOn(lifetime())) , _style(std::make_unique<Ui::ChatStyle>( item->history()->session().colorIndicesValue())) , _delegate(std::make_unique<PreviewDelegate>( parent, _style.get(), [=] { update(elementRect()); })) { - _style->apply(_theme.get()); + + std::move( + theme + ) | rpl::start_with_next([=](std::shared_ptr<Ui::ChatTheme> theme) { + _theme = std::move(theme); + _style->apply(_theme.get()); + }, lifetime()); const auto session = &_item->history()->session(); session->data().viewRepaintRequest( @@ -269,7 +279,12 @@ void ShowTTLMediaLayerWidget( not_null<HistoryItem*> item) { const auto parent = controller->content(); const auto show = controller->uiShow(); - auto preview = base::make_unique_q<PreviewWrap>(parent, item); + auto preview = base::make_unique_q<PreviewWrap>( + parent, + item, + Window::ChatThemeValueFromPeer( + controller, + item->history()->peer)); preview->closeRequests( ) | rpl::start_with_next([=] { show->hideLayer(); From 268613e1dbfe68bed3b0b485d026622b0eb14a1f Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 04:50:51 +0300 Subject: [PATCH 45/73] Slightly improved style of voice record bar. --- .../icons/voice_lock/audio_once_bg.png | Bin 0 -> 496 bytes .../icons/voice_lock/audio_once_bg@2x.png | Bin 0 -> 895 bytes .../icons/voice_lock/audio_once_bg@3x.png | Bin 0 -> 1304 bytes .../icons/voice_lock/audio_once_number.png | Bin 0 -> 269 bytes .../icons/voice_lock/audio_once_number@2x.png | Bin 0 -> 389 bytes .../icons/voice_lock/audio_once_number@3x.png | Bin 0 -> 529 bytes .../icons/voice_lock/recorded_delete.png | Bin 0 -> 614 bytes .../icons/voice_lock/recorded_delete@2x.png | Bin 0 -> 1112 bytes .../icons/voice_lock/recorded_delete@3x.png | Bin 0 -> 1556 bytes .../chat_helpers/chat_helpers.style | 15 ++++-- .../history_view_voice_record_bar.cpp | 45 +++--------------- 11 files changed, 16 insertions(+), 44 deletions(-) create mode 100644 Telegram/Resources/icons/voice_lock/audio_once_bg.png create mode 100644 Telegram/Resources/icons/voice_lock/audio_once_bg@2x.png create mode 100644 Telegram/Resources/icons/voice_lock/audio_once_bg@3x.png create mode 100644 Telegram/Resources/icons/voice_lock/audio_once_number.png create mode 100644 Telegram/Resources/icons/voice_lock/audio_once_number@2x.png create mode 100644 Telegram/Resources/icons/voice_lock/audio_once_number@3x.png create mode 100644 Telegram/Resources/icons/voice_lock/recorded_delete.png create mode 100644 Telegram/Resources/icons/voice_lock/recorded_delete@2x.png create mode 100644 Telegram/Resources/icons/voice_lock/recorded_delete@3x.png diff --git a/Telegram/Resources/icons/voice_lock/audio_once_bg.png b/Telegram/Resources/icons/voice_lock/audio_once_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..62778676ce6400ba75ae200f873734be4be7d0ff GIT binary patch literal 496 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEXvcxF~mY} z>y(3i?gj$wk$3hq>?l;8DA0dk_6Iq+!v~EOTV_x0*ioc%^KY)l6s><J^MsA&o~xPb zmwu|S-sFdLU+(Q?nOa>&=ZmkGX3jG6El#eFo0MwVwP;)J{*{3ut`coc3Ug{-?0o<G zut7je^P*K+E?&Ri%~If)mTGBXsP@<*>Ga*nQ#O2<wCT{nT^-z&l{SL1GUqDJiEr}0 zz4xNR_a_^7oVKoFK4kk&;mT=g`DwlDUMJK(+<oHazSEnZSe#>XdTTd(vu;S}T?d=` z>l!(SwkdgDV*9nGS)<_ocj*@sDo?!&Y|Ofq`^hFf_S9av(#=72`Mk<~k3)ZanXhv4 zAnVjV=6m^m>ldxQ5X~;2HZ64_e`fYHHraDE3^wOyFYA2j`O5L&?Bc%GInr%`*G*qK zpSBP*7MrBnrBt;`$6Kn=`jB<uMDf1et22Es$6R-1XXst!yf-D%E$^rPCw^(24I&KB Rg+PJL;OXk;vd$@?2>|hXzrX+h literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/voice_lock/audio_once_bg@2x.png b/Telegram/Resources/icons/voice_lock/audio_once_bg@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..225d6af3b8da0d7bebd0f07b0fa325f91ba8aa95 GIT binary patch literal 895 zcmV-_1AzRAP)<h;3K|Lk000e1NJLTq001xm001xu0ssI2*kEqZ00001b5ch_0Itp) z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NE=}AOER9Fe^SUrz%K@{c{u@oW- z@fC$A=p=L!4Hb#~1&Y=A4+;&PAK@cZ3WbhRLPDq!3E2&@B2nxnHd*ic<dw|5%jM4a znD^aeZ*g<(nKSb|_sq;WXGWp;dA^wklo#+-sZ@bLAR3LjTrRWOY_VAI-fp+g&(AM^ zpTS^ItJP++*#(2MbqR;V`Fwu0TK%SYy4`Lnm9p7vY#5Z*KA*4AXi(5NG<ko2&tx)s zy`B<C-ppt;Rw|X<Zg&X9^8NbynoK6;!DKBw9?xhrVu3zqTPl?v9v);tPa0s^ZZ?~9 z2<&a0P6wOdB;=U}u=)J_WJi?mF`Z7CIbo)5?i(>v_=#ceu!?WEZp1vqGS<_X`T5d> zJtgjWKbdOZA>LfM!|8tjvEVp9slGTzp(qxMPN(xgd8bdEPKS}3&F0DRks0X!?<SUr z;|ICrmzZ5V9v6RdkhNOv)6<hQ5OO$W*1U;t$RNnU(u9J+ATi=BI2;bbNtiN(W}@XR zJU%`WM1c^hEu!Ttc)ebNC=f!`N3@&;yWLI@1wzaTkBo7(Al~@`p?~NhX+mnX`s!c3 zZ~%=)LwX7x!kK|+ISY%$f*=ZnhQlGzau(+EIYAT%p#~ya&cc7^q49Vu;R3hY%{gNb zIAkpeLQwU3Jz~U7Kt@MiCxnDG1Xa0QCJo$#dcBV0jWiqr)W^pMH{a}mLZOf}o4q!d z%kd<H`+{?9(1xmexm@z$gwq7h6f%U+oJb`25W;y&o((LNN@cZLy*DSsVVp>*2*C)o zce~xbA19pCaayNkv$r#uOq0pv9-OerBasLjo4qw^@0*88_~xqO9d{IkLg7|^!n$Fe zDM?S_R$#qeUqcH!9D9mk6-)9ED-8xiHk*BWd%J)Zq90Yf5#v$HsJqkYbid!Hp@po8 zJ7k&6a0GnG#W@DSdXL3oe!t&pwIT!Jjk*|h7HU7dQQshCwpy)|S@Vd;kK+4!;16gm V2KWrE74!fA002ovPDHLkV1jt{gmnM_ literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/voice_lock/audio_once_bg@3x.png b/Telegram/Resources/icons/voice_lock/audio_once_bg@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..1d82b2d6e73cd0cec973a1b417096b19ab1e17d7 GIT binary patch literal 1304 zcmV+z1?T#SP)<h;3K|Lk000e1NJLTq002k;002k`0ssI2+K(g<00001b5ch_0Itp) z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS<f=NU{RA>e5Tg@wVK^W&1<s-uF zDxwr+LloU~QL^AqKuY%h3pN%kSSgXRR5msiFG<R0ws&z$lCPrM^;yLG{@(Z2HRrkK z`#f{*8Qrs*IWzOj?>95&nP;A7PF`N_$&Em61Z0jtzC7WjrKQcy%}q^Bm6er9<N5gb zczk?JCX?6K*Rfda?(R-r@65y+8yg1(2KxK^dwYB9>+8*NClZOXv$Nm-pOcf5&(BZu z`dKIqg+h~)lLrR}f80K|x3{yivu$l{SwOGbWkW;5{QUgu>#JKvwB6p`-r(S%ZeKpV ztf;71SXg*}f2Ytm@<&HU(P-2sCSo^ZV`Er6925*?e0_Z_FE3+}i~UMW7Zw&SE-o6v z;V!tky6WoclE^0|8soRSyUPvULf+fk+sMd>L~gCEt>@?G7AT|@Pft(h=QD3k{|0Ml zXz1zbNg8Zhf;TocN=iyNrw((Kbyg|r;AV5)3M>Zz-__2}PB<L4tm#9AmX;Q1ukGz^ zuYEy^|JuTGT{7qrKQ+50pL7N2Nl$wKcHy+Fpe3-sx!k*9G0C<qJPsD@5;tEO>_Cql z%We*v%dtHPn_ZH1%gYwFva?AG{&b}W$iW#0A0^}YDvdx=0_Qi~N&A)gc6fNWxVSj; zeK6nj^z`VSyLE^`%LkK#5vuX=aigN|_wdF@S~K#*Vp}RGptd2MG5DCiSt^pMsj2Dg z>?B|*F?h~M4JERf^FfKhAE*Qq0y2}B=1f{vR)%vIX`@6IzSpX%DiNw?#^8<?%M?n( zi;gc%1pGsYffCN3hQz>IEK@68TU#pv*31|JB4U|ZX`Hh}z(0prd3m`ZF|k0oG~6>H zX3dN#s_RpHUS3`diNWX+%hXDn5xcp$QHzX-7JIaq)hxw}iwm(#t#mvd7XfQbDiqw` z-&a>xi#1e9!yXh@qh`jy;q>%W6(%Ci%galV6^bY^1jxk(s-!bLAC%bU=B6rSM4Skl zh*_O9f;7;L@{aM6B*UXY$j})>$Ls6sq*B1Mhlhs<wGxn&7>W^LA(aB2U0YkTixA(U zq&34X7QS8G{YhuWz<y?C#_kwoyWY~$(!;}p0~GuF`|P93E)bCu#7`WsLe;*$K6V`J z0uelM#wt~NWo3mO3Zp=rMaZeyE=jmRg1o1BiZQ?u8O#VE!=5xTF~PWgSVZB525|(~ zU4*3G)YKFUAQmAoGF;vlAgoeZ?CvbEJPLtV2KS$I5xRU?R8+LJwdE0($L3&#yJ{{8 zm^4FhZEkMPBRJR1u>zUriclRL9rZu-4sF5tT@gy@Y<qjVpEok0*?Dwent(|H2KDOd zD(=R(URrh<!nW|V3!4xyFY4~@K0ZFS1JP+6SOu^HU0O`$pzW7JQ!(CY#0LyYj%{}P zaGlod=;(mX^kQ4WL5BZGxReBSm^$S{>SIfYL?XC)fCpC;EY}kJfjF(h$Amw3ppb|( zFIi?{1PbE9h@jTh)ggF=2g(g@O+4_k!y}F7`T3bN$z^jRkQ)ItM&K`hc6KrbLxH3K O0000<MNUMnLSTXm?^1~X literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/voice_lock/audio_once_number.png b/Telegram/Resources/icons/voice_lock/audio_once_number.png new file mode 100644 index 0000000000000000000000000000000000000000..61e22f105da97f4ed4b33d91552f4b9cd957ce76 GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfUm3z84hFAzD zCrGd^R&@9*@Zj0Abt_gxY)ooxXkhp`?c|9QcXpM&wwGXGV|!%Y!P&oM%a$)6A0Iz` z`gCJfL`1}g6)av4jbA)DIr-zqkNR<Y4&<}Ah|PCA@}hmU<VCi-yUXAI{{H^^`}^(e n>_2(Z($YSe_P>%jqR7BdJW2j{^zmQ=kW)Ne{an^LB{Ts5y|q@- literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/voice_lock/audio_once_number@2x.png b/Telegram/Resources/icons/voice_lock/audio_once_number@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..15047cb489de2c2d3655642ee1b618a6d63b20d9 GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@H<Xr$#jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(;Zuz(rC1}VI4p2GvA-g~+@hD30_ zon*_^Y#`A#c^ikE>jxG|<Ic^Kqt`un;rr;xJI-BJRl<P<1%fiSwj{ATD*aUOzMub5 zy|TXIhs5Cq1`a4{2xls<l6r3Ads*l7v&whB=jC}6bv)kjde?QkAg@WXt~m!pTsP{R zj(hfb&8n_Po|m%L)`wmzy?bx=GR2ujWyRNKFExzXZ0@ykTkhOiKBw<amGh>jO1cKd zUS|(J_55(;pFe$@|M<M{dvRvs5Bb&{21kyT9G0BtHx%t#juqZ%YD?UpT4m`!DP@-0 wWjBt8svn#@B-$JWVs><BD=;uYP`%#+-eZ>|h0fLfR|Extr>mdKI;Vst0JcAc^Z)<= literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/voice_lock/audio_once_number@3x.png b/Telegram/Resources/icons/voice_lock/audio_once_number@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6e39511e17a9cc3d47e44d8e9ecab7656e4728ff GIT binary patch literal 529 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1SD_us|Wxo#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz1|Sip>6gA`6MbbAj}R_*EH7?Q#I z_J(a&vx5ZNgB{T~Z+JTB_(<nm?&w`BcYwQsssFL+mW^A!GE6$h9nqorXXTOD$ix{p zatzP$v|U#^qjF}?XWMwC8K+srSrix;IUE?61R5BSnJL^g+|~`tGW(A^U;nx-cY3Pe zw9|$s40=>NpH=?*xqIIE<*AV}pO56ox(43=9_{(W)Hm4hWlYeu{Mc!!OC+i;l*&%` zV4S^c-E9-z*fV)L4|tBd-+BK%bJh#5vddo=KMuZM{-<ibobl({_|VWz;ejIao=<$) z$-XT&|NDVNiANS;B1cVpcQrCu9qZ2Dd$c{VVsG5`hVz;^>}vZA^!9Iz4GmhR;lpL^ ztYLMmK|NK|O09LSqKItrfytXhWG5dwC(zYr_`ox=t8e4R{>L8nG3)pj<oy1-KPupO z-1_jyX-_OF=S}|jlHF0@O6lHjYgcI<FZ7G&k3I0~`SG`9i|-$lKo1RQ7|qxD!0o#2 Vw#!!Y_pPAl@O1TaS?83{1OQg1zrX+h literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/voice_lock/recorded_delete.png b/Telegram/Resources/icons/voice_lock/recorded_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..f204f8f2206338ead7b6064d93547a8490ff43e8 GIT binary patch literal 614 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgf?1HC@V~B;| z*^u4q7z0JVN~j3Abhu}@E)Q6F(bL6wiriEV`v=S+Rk~B>{b1?za8cYo;l&f7j~*F& z?v}otoh*~Q?vkEb_WHf&X4R&hx8ypyyftXq!T=2s4i*zBUX$gQSKfcW{dTV8-jbCe zTCwY|KP~!M+kG^taZAujkJYI+u4aX<4V!wZ`ZQ3yz#?O7)X7k$<c(@GeWZBU46?S~ z$}#(0v#)CJIhMTb(zkWQx@Vtdds4PL*F-8~GUvaByLs(Qt>(;0v(FyeT~jd6Z+Y^@ z88yuh3w8u(oX8eg8@Bpp&Locec5?l~=bnE)m@uJWZP@D)t2q<9P6OR_`K5}{M30os zk%uJ0RD=|H7*p;zSt_47nqhK@iD8!2rR_awn<d*;1^wOkVCuxf4;$Y6?_+V?5VbZ* z*`R9gJgY<YnHwYS-I6lZH(PXnZqEh2a|iyrT`{hGe=xy7hVS8y`|tPXG4d$e%-_!T zNwLIAw$DRrYE^=(r-@W+gYUG^A1fa|ef{;;(;`Dw_JCb6dY^yJdHjC)e9>KZ^VBB4 z{93i6N5b<!iqX>|%PHrc8;4Kw*c<o0!ltg2-A7G$|NZ}a-qhuHX3yAu{PDpPM^!!m jL#Nm6_~VI>?T!92^7ip(me+*^gW}lJ)z4*}Q$iB}!$SPn literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/voice_lock/recorded_delete@2x.png b/Telegram/Resources/icons/voice_lock/recorded_delete@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8bebe1a61bb735034f539f35c930514b00020427 GIT binary patch literal 1112 zcmV-e1gHCnP)<h;3K|Lk000e1NJLTq001xm001xu0ssI2*kEqZ00001b5ch_0Itp) z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NF!bwCyR9Fe^Sh-3pK@`<-#~s84 zMMW@hK@`+L6eln;6*My*4a5&{iOdZI5x>B|z(5R4L<B)a6c;cuFmMDHP{D<ndGGix z9E$3ty6w^6(H%5Z_ue}9)T!>;GBUy^R3KE~OM#J*k?rm6$H&J%mgnW=Wp{UXVqzjQ zGxL|kT3%kZ(6BLVZEa;`W%=dgyAz|MqibtxlIHsQ8X{>ai;Ih!o0~<RnVFe|g#|4j z&DFiVJyBzPeB22-8jXH_ej+R$k2}Sr#~z79USD64>EhzT9dTo0LwMKL*1AV(-iTIr zuND*(6c!dD=KlWPJ(2+x6&3E0n%Djt%FD}JTwLtw>CvL0P*+zMjHy)W{rz3@s@2@w z-0bXZSS~Lw-`?I-7s`i+htt#3A0Ho@-LX16JS>9$+#4wz(_0<o<>dzl2S3LK;ALfH z*1Vx5RNz+>=<DliX=w?bs=mH{XlN)Xj{N_aFd7;ff?#1fy}P@^Z#y+L<&I;RsYM&i za{c}N8c;_^M{8@VX2i@nI5=2URi)Y6+uJKED`7N>Z6L(ev8JX*&C%W6eR_I&etzE8 z)~4DgCntAyc3{uR$x-dq)zwmkPO9Bn_DYC|0@2yoi30W*0|NspDC9vE>sMV}ooZ)) zZf|c@yR~c}#P&oKi09{LDU_C$s-Pt$B~rz{QMI!<0adSB4oZj&1e8@W7CQ;?8&FB8 zWdot7rzcsHwIO3ZG7wM^3>yJ#(9|?+9#kQKN}t$8N#jIF_|Z#F(j32i(2p93(kCp= z`T6-wz?7Oo?t~s59yH|$$bw<W5XVuc>@eCA!cSLJRHS+(4eT-r5lZZ~Z!;l|x;kpM zgmB)F!v?*Q60?9zON6qeBF1kL!WI_0eL$$cJ%>*t#Ga&w5OpT5bVag~1dJ?eggDlO z5(L|~4~2*;K!Tn~B#4_#CRG>h>`8hQA_{RO)BODW(b3WD>?{*sU0vanje|YjG@`(U zgi^h}%Q)%DZhv!g(|6;44RE3o1X=0aLCiyjsSKYmP_!X)$5p+)6fzUSS0cwy;;PBK zl-V#nLxz+mCnwMx%y6Rh!a$3`B?+3#G@-eyRkK29v%kNOH!gd|#>T7=?iOsx8yg!D zBOva<@O~Y?jnDe}dMp-0*y`$PZ*T9}*%^9lY=wZPrY2maNhCnLH1Qg<va$ja-+pla zhwZl4WM1O17|qSiVWZ=h6K2b$r6o?{#$5K-F;2~J34!Yv41~w--rU?AA0Hd{Ku+mG ed#J#Fp}=2f*X$qSd%yPp0000<MNUMnLSTX}EABY} literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/voice_lock/recorded_delete@3x.png b/Telegram/Resources/icons/voice_lock/recorded_delete@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..db0067c534ed82bdcff4bcd50e337d90956e69fb GIT binary patch literal 1556 zcmV+v2J88WP)<h;3K|Lk000e1NJLTq002k;002k`0ssI2+K(g<00001b5ch_0Itp) z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=en~_@RA>e5T1zi2OB6odZ{m?4 zh<Jwq5+ovFf-u3vfW*+m$b<<oHu4upj5s5~NMa(0NJu>584SJRO}x3^J$<vzm(up` zZoT`Q8@)%X)?T%~^{rY}T~*ybez-q318xS~47eHi1{v`41;?PEpsK2>{QUg*_;^1* zeTet>_nVuW{r&yv>1hbQ2*XaF{{H@*ot>wrr-<9&@BaRNU|=9BD$33{?DZ8A5;8tM zZjg^+w!Xfenwn~FJhpio8X8i<HPu{NT0&~<ibj6|Snyt1SvfN^!yR{ac6N7n!HtzH zr=+A578V8s1c<V$s|#f*&A&nz85xoB!L(^?Y%~&9QBl#s!GUzdT4JP^qc*%?^!D}| z$F8ld6=D!FGc%3%^|@teXeb9)Qc_|ZGB7ak;o(8L<2hlxuLnzi5C0ke3&hy?;^Kmv zp5>R9m)qN0u~A%!-mDO4qyrwfd3kvrmMrBd)YR03$~59xvtiFUIXP!%XP@<be0<#A z-hO_5{>;FH9&6X$-ky}o9~Te|Lh?$$dntBwbo^Bl8o?kW8;D(9U3vB5uz@`xMMOl5 zjg6tW|9BB10EB^H5R${Gbm80#xEXLW@EtP{78b^bD4(VPS0<5>kv@g^&v}1;KelSv z&ehk~`x-AhJ6k)dPE1S$2M7BQE-Ncb9@AS}TRuek<$8E{Sm0V)TTQ`v-z&1a*w|QU z=H}+&C?!orz+azTyon_a4I=9b1qB77XJ}D+5X=!fIyw?xh&wScQJO5Yx3}X+hF?od z3+qJ&?Vmq?Vt=%{x|)%ZA$mnfPEHmLLyOWj0Xcqqdz11gEiL`%8cU0uh%YZMb(a|s z7AJ#)gCCthgDXl*W-+U%sL(b0OlfY!v}HqlaYjXnnvsKJOiYaKsG^L;J}D_lWEK(< z61db44-ffYud+E}aK`|;F<oC@Gir2nG&ePwm5RL>D_JvJieDn8U~4hm-QA&FB|he$ zt29CkC5<aR>25?YO^h?AOANDuUou!G#^u1EMp(hdG%>HG2&X&<mWgrJ7}N=3jLmp1 zv469{S>WtAU5Z@px=T5N<I9%+Whvr$6&DxBY1U*O1U$+<8ZcYV0$XyOJ3Yq`2g6HP zOpG~*0V~;93?MjNinwRTlS(46Kn#~>ywB1lhC6e<V{>A}K#5^EufmpN<-ySm6b&1T z2PI#OC^nu2)6X%uV;Cg@4UA(|Xuv?xu(8C-ZgB{}K|%g9C|DuJ3nND$kQ}Q*12(L| z=8NAUi3ctOh7$v?f)!#sVjO{h87Br-*n&w%5jbBACk9@HuM*=31dLa3UIR1(*07~? zhrn)~8!<-W2qdzVm6fNbC#{JOI7F`ro12@m{a;*MRQ}bPTnN@iOxLX!WnEpJ9Bgr* z(6z=_1M~Cqcr&7V@^5QvTUb~a9Uaxp3mi^OO$kI_U!N|7{YreCA*c{=7hpTa+S-~x z;0DEle=Bp0OA(NtW!*wF(uGS=ffF0gf)!$TagJC0;+KOE<yQn;8R4@z@nCI^Ss{iZ zIX*rXVB1Fwnc_Q1=ZJw4gZYA(WDV=*$;pW{jSE&rOd*DQZ{v7IEOBKoW=h$M-m74d z*v7_&xNc}@u=kBYb91veXCP7fP^hV?k>wZy-X4U9hkqRpQ>(kXn?3jR^jLFi@q0x? zu)MrnTwE-uSd?dHXV1^iMPpXLR;#S6j4z4t^v8$A)|Pv-=)djp(GzxhoLzfmEE@(t zdi))eT@pS9!)e-HKAJbMa&9N3n~wDK^vTIdd%0l`U0z<U3ujzuagHefm~7S6)oE#I zU)eX}RSu@p+}s?#Eq;A{RUq7^n*lciZU)>8xEc6P8TbbrS#tjwMqW(-0000<MNUMn GLSTZE7@*kz literal 0 HcmV?d00001 diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index a7f94d301..2ad067367 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -1063,12 +1063,17 @@ historyRecordVoiceShowDuration: 120; historyRecordVoiceDuration: 120; historyRecordVoice: icon {{ "chat/input_record", historyRecordVoiceFg }}; historyRecordVoiceOver: icon {{ "chat/input_record", historyRecordVoiceFgOver }}; +historyRecordVoiceOnceBg: icon {{ "voice_lock/audio_once_bg", historySendIconFg }}; +historyRecordVoiceOnceBgOver: icon {{ "voice_lock/audio_once_bg", historySendIconFgOver }}; +historyRecordVoiceOnceFg: icon {{ "voice_lock/audio_once_number", windowFgActive }}; +historyRecordVoiceOnceFgOver: icon {{ "voice_lock/audio_once_number", windowFgActive }}; +historyRecordVoiceOnceInactive: icon {{ "chat/audio_once", windowSubTextFg }}; historyRecordVoiceActive: icon {{ "chat/input_record_filled", historyRecordVoiceFgActiveIcon }}; historyRecordSendIconPosition: point(2px, 0px); historyRecordVoiceRippleBgActive: lightButtonBgOver; historyRecordSignalRadius: 5px; historyRecordCancel: windowSubTextFg; -historyRecordCancelActive: windowActiveTextFg; +historyRecordCancelActive: historySendIconFg; historyRecordFont: font(13px); historyRecordDurationSkip: 12px; historyRecordDurationFg: historyComposeAreaFg; @@ -1111,16 +1116,16 @@ historyRecordLockArrow: icon {{ "voice_lock/voice_arrow", historyToDownFg }}; historyRecordLockRippleMargin: margins(6px, 6px, 6px, 6px); historyRecordDelete: IconButton(historyAttach) { - icon: icon {{ "info/info_media_delete", historyComposeIconFg }}; - iconOver: icon {{ "info/info_media_delete", historyComposeIconFgOver }}; + icon: icon {{ "voice_lock/recorded_delete", historyComposeIconFg }}; + iconOver: icon {{ "voice_lock/recorded_delete", historyComposeIconFgOver }}; iconPosition: point(10px, 11px); } historyRecordWaveformRightSkip: 10px; -historyRecordWaveformBgMargins: margins(5px, 7px, 5px, 7px); +historyRecordWaveformBgMargins: margins(5px, 8px, 5px, 9px); historyRecordWaveformBar: 3px; -historyRecordLockPosition: point(1px, 35px); +historyRecordLockPosition: point(1px, 22px); historyRecordCancelButtonWidth: 100px; historyRecordCancelButtonFg: lightButtonFg; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index d878583eb..1f812250b 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -312,49 +312,16 @@ TTLButton::TTLButton( Ui::RippleButton::paintRipple(p, _rippleRect.x(), _rippleRect.y()); - const auto innerRect = QRectF(inner) - - st::historyRecordLockMargin * 2; - auto hq = PainterHighQualityEnabler(p); - - p.setFont(st::semiboldFont); - p.setPen(_st.lock.fg); - p.drawText(inner, _text, style::al_center); - - const auto penWidth = st::historyRecordTTLLineWidth; - auto pen = QPen(_st.lock.fg); - pen.setJoinStyle(Qt::RoundJoin); - pen.setCapStyle(Qt::RoundCap); - pen.setWidthF(penWidth); - - p.setPen(pen); - p.setBrush(Qt::NoBrush); - p.drawArc(innerRect, arc::kQuarterLength, arc::kHalfLength); - - { - p.setClipRect(innerRect - - QMarginsF( - innerRect.width() / 2, - -penWidth, - -penWidth, - -penWidth)); - pen.setStyle(Qt::DotLine); - p.setPen(pen); - p.drawEllipse(innerRect); - p.setClipping(false); - } - const auto activeProgress = _activeAnimation.value( !Ui::AbstractButton::isDisabled() ? 1 : 0); + + p.setOpacity(1. - activeProgress); + st::historyRecordVoiceOnceInactive.paintInCenter(p, inner); + if (activeProgress) { p.setOpacity(activeProgress); - pen.setStyle(Qt::SolidLine); - pen.setBrush(st::windowBgActive); - p.setPen(pen); - p.setBrush(pen.brush()); - p.drawEllipse(innerRect); - - p.setPen(st::windowFgActive); - p.drawText(innerRect, _text, style::al_center); + st::historyRecordVoiceOnceBg.paintInCenter(p, inner); + st::historyRecordVoiceOnceFg.paintInCenter(p, inner); } }, lifetime()); From c686ac860397f1117e91e0c2fa65d289bf15e287 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 05:04:44 +0300 Subject: [PATCH 46/73] Slightly improved style of ttl badge in voice messages. --- .../Resources/icons/chat/mini_media_once.png | Bin 0 -> 561 bytes .../icons/chat/mini_media_once@2x.png | Bin 0 -> 1011 bytes .../icons/chat/mini_media_once@3x.png | Bin 0 -> 1465 bytes .../view/media/history_view_document.cpp | 41 ++++-------------- Telegram/SourceFiles/ui/chat/chat.style | 5 +++ Telegram/SourceFiles/ui/chat/chat_style.cpp | 6 +++ Telegram/SourceFiles/ui/chat/chat_style.h | 1 + 7 files changed, 21 insertions(+), 32 deletions(-) create mode 100644 Telegram/Resources/icons/chat/mini_media_once.png create mode 100644 Telegram/Resources/icons/chat/mini_media_once@2x.png create mode 100644 Telegram/Resources/icons/chat/mini_media_once@3x.png diff --git a/Telegram/Resources/icons/chat/mini_media_once.png b/Telegram/Resources/icons/chat/mini_media_once.png new file mode 100644 index 0000000000000000000000000000000000000000..8984491b7ae14c859e3ee0d51a336e8a75197115 GIT binary patch literal 561 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uuz(rC1}QWNE&K#jHrvz1F+@YO zc9Q>U#z2W<{f?cV^pEJIEMC@;vu>$}PQ>{slb$d~XlTnHXgZ&ed%8&|^28~xlU^Nj zr%duFdEY$K*!cUkTJz6)_CL2Yes7t+#U=J&g2D9DoJ|QvGpC(idMl*-Vn&J4%$ohL zORTQGF8xuqd++6!N0JOnr%ec2S+f8BMD6LP^R~~vmA1LkZoa)-zt>VH#gl29&p$6V zkl3K39qcLDdn|1A*8A^GrOtLQbl-e4M@OuCN~Nu9v=h(aj!h9dNpD<~6eCq+`1;)z zKmPcl#7c9C)AW-m*It_ni4@A1&p!L;qlH<qg^b4ft66%}yFdP{=|0*N)KRwk?)&dk zpDf;g?`Xoj_{aZxgPJz*eNIqy{ofI{K7DJH=fZ#kyF#><_OLNEe*XF9W5tw!D{Re) zyYId$vz~o+*_NlpDlAgbQ}32o_3oDGKOVO}eA%QT3mJ>Ux8E+i{#w<|!)`wNA&IM5 zp*wl5?}}QhH=X<Z=b~SWl_s7jusBi|aQ*exn>kI7*Y>(8i*Q~1^85P&S;e~j_A`AR jDPMlM<@Q@GnZSPx`>!r6lAHQj7!+Neu6{1-oD!M<P^aoc literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/mini_media_once@2x.png b/Telegram/Resources/icons/chat/mini_media_once@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f8514d3af5b634e8db539d644ce7ac5860077641 GIT binary patch literal 1011 zcmV<P0}T9$P)<h;3K|Lk000e1NJLTq001BW001Be0ssI2{21+{00001b5ch_0Itp) z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91AfN*P1ONa40RR91AOHXW0IY^$^8f$?T}ebiR7ee_Ryj*+K@^Vn#YkMh z;D%caQ3MM?1wj$DQ3O%Yq!5xO#6J+R6R}YPDN<O75JbUJENn!<t+2GP5-SB2w<Ic( zMH8d%eeWF{ZgOXCuD%pEGv|C~nKNgZUpmb{lgVVYT8&2I%gc*qp=`jmwzip>nd9T* zx3{<7|9&4IA45Y!+2l0v2L=Y9my~9FXJ=>S3dYCBr>3Tgii+e!wRKHR&Eer;hEi;w zo}NxmPuJJiD=I3O{MgtSA+N5k1_uWjUAXA&?R|K7VA^A`*viU^&1Mrh*wxjQN~IVc zM-i$9V{~-%{r#QL$z*b2VL|S!NOELk<o^Di+3<S3d}MojJNzZw&CN|`XD1)Wqawj} zc6LZM9*^hd=4PTwOH1$W?g(*qcBaMg3>8qiw6uhCudS_Ru>Nir7Z*u;Fc?I#a}e4{ zs1gpasi}#DK5HiE^?Hs9by6S@AosVow^fj^y}7yh`ud6_HW&;l$TXHDNeBxW=;-K3 z<9%)N^76K}wg^Mt;o;#gX10GMKFOd`a&mIGaH^*3>+9X!T>?8C4la_21qB7m%gYA` z2W4etx`~Mil0goLWDxi6?rxl8etuqy0jJYRFrUw-ud1pdz31oWA_J(^qoX4cS4l_8 z5Yb|>NY&NVv_Wwxp+BR9!(kFcc}bt2pR~bk|4f}yid8a>BHiBJ5`rB?DezrNd3iaB zpl?bnG7Sw4-&G{SN25_<ot&KLF;!@TIfXRE?Tf^;(@~FZw;MN%4y1!pM2WJhr>93< z%k=a#Au%D;k!f7k>Cgkx7>Z3xOUvWqBT5qeS-}(&>g($hiG)Vi(1m`IZ+^d@3_L$S zqq&NmQRARjqlOzB8#$oj;^NE8OR{lsaZy)S#{sF5&=K$?fCj{{u&|JWZEkMHi;8TZ z6#M%6I3NKD;}&j_Y$OuN&(G%r@fMOluvS-Bk!pOXj5;|v$>tUA(r&lQn2IHQL6VR! z_+rLxY;3q(F4Q@<nYXsKqS+800f37Nl?noyI4XtNU<(+-NWkj>FEb`oTU#3ng@D=L z-#44hjGldgXA33<(=K1k&CSW>D=RB8Ex6~C!}x17D38apx3`C}N})iM`}_O(=>Mdm h2_rZqB_-d|^9MrUT|a$+sx$xq002ovPDHLkV1g{Rzg_?U literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/mini_media_once@3x.png b/Telegram/Resources/icons/chat/mini_media_once@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..3900061be980c1112d770648672640ff6bd25f14 GIT binary patch literal 1465 zcmV;q1xEUbP)<h;3K|Lk000e1NJLTq001xm001xu0ssI2*kEqZ00001b5ch_0Itp) z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NHBS}O-R9Fe!SxYFbQ53$8Lmqh( z7kP$43CSbME98}dVt|pMC=5hmV1Ob9C}e;_Vxp7?p}dNa0VB`6Bk%XU-?`_u@3#N* zpZ{?=-R>E!wf9=zT6_O%ueJ6*-@g50KRtQ=xVX5)#Kbr|JAeQ6b8v8Yd3kAQXc!q8 zkq0P8OHWTPEG(?1re<wz?T4n{^YgQZhld<!89M3d>Few3n%wv>mXVRc1;<8aXJ>nR zdvmAcjKsyoEi5d2Fw4VSU0vDR+cP$TgM;tx?x6AZ_SV$YWNK>42uNU!jg7mzyLqgu zhTq@c&(6-Ub7Ny;t*x#8{{CF_j*bo*VP|J2At8Y)COqQm>bkPBLSqqndwaXFu`xC_ z*3i&U5U8%Mjwq@LETg!%SWxkU0F0fVpEE#UafpI~f<A}}F?M!#%gf7LsQUVPoDw1J zU-O}%q4)Rq48-*GG>(`keU6ZUfk8z@#pB~6gNcyh$Z`hU+}uu1PH0W+a8*^6*wt_V z$$*cK&&I|EgKTMONdz<y78Vwpo13)G<>h5cN{R+iSwk>CGc!Z*k+%d6-N3*Akp^*l zdn+|!1pPEJGV1N^1vtDZC@9b-9~l`*d-MAGnwpxbP2n%*P;acPth50jM3$D8Xorf5 zinJ+w^;}L)4($z6v(zXyF)`8C*Z(v>nK~u@gv0NwtSqEZ9L9r#103&9@X5=|i{75T zzCMwl$mSCh6SOX99B+~8ykcc#Wi)71R1~i$HG%qneSJ+Us_F9ba!N`TNr&_C@v%ao z5QM=Q!MWvngOS?WT0wPMz}?-wr>6%+DLy`4HI7<C<F>W6(b9ahxw$#A6cisG9!g3| z=p{*V2q8#PF;)oYl)k>cwAJzPahm0$@v$NzB2a^ehKBa{_cJpy`6RWEBX<)AQ1Sq% zWMUBL+9Aj+4kmttl}Dh8(~9_93L6_6dg$=*kY>M{etLSkxw#=$R1TS$nGqgcCQ3bF zbwi-%B!+BlZ50Si!Xw1+Bdl%+G|I#fHcUb97!EvcSY%oU1lEtwL=55kDCix-gp-pK znbrY;e5O<?iJ{ZeQ^nTS7U4ml8qn-l)2M)S%<S#$DUg>iN(?6@B@tQ&1g>(pX{imt z6I`cM^z7^`N!Aw^7xW&A^l5&6o*+od)WAp6lAN53tF5}7Rh6yb;bCIf+S)ogI-0N| z33}UUT8uh!&FJW8e}6wNxR7TZ!cbvhp%@@q1~)IlqOK8IKEd4OeivTRcmV+c>R6nb znxgZHXaJ5NUM)xvfIyLw(T_4!h+{<J02W94R9#&y5#Y1M0|NsQU$jrTxw)ThM1_Z@ zr@g(stE<b;&rblqv$K<S2$e;~iPLT)BqRixMQsIn8I7JcdBo%5;v(%68p6E1JZ(Bs z=CC}b4Hxd;@dSo9CE6#@EiEl*=cJfsWl^?EOG}vt5Tt3OJyw*<<I_Tv@d@WHEiH{J zEM^2jGdDNK0HP(AkX-OExVyW{K!C-KHZd_#Qbxd*qoH7+@Td|V9xi4ve`L_6OioTR zKx!6`Yq+?e`Zzi|3ObjcpU;3GB#=n|SQ1ac7~aCw9RdSNSY(Q$qodW;)xp6*yq|Ev z@rX-=LEsIPZkoCB!XsD>ZgDgyAC2mWCuuHXWo0E!IHC|$ojWUY1fQJm3)22+d^neB zQjD6XrzhTx@W7z)9?iEyVvvc9%sU1$EFwnz=L_xycoD;&FU`%(INk*MKOues(1;fM Tj0eD$00000NkvXXu0mjfuA7-D literal 0 HcmV?d00001 diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index cf5560009..f6e60f877 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -59,37 +59,6 @@ constexpr auto kAudioVoiceMsgUpdateView = crl::time(100); st::dialogsTTLBadgeSize); } -void DrawCornerBadgeTTL(QPainter &p, const QColor &fg, const QRect &ttlRect) { - p.save(); - auto hq = PainterHighQualityEnabler(p); - - const auto innerRect = QRectF(ttlRect - st::dialogsTTLBadgeInnerMargins); - const auto ttlText = u"1"_q; - - p.setFont(st::dialogsScamFont); - p.setPen(fg); - p.drawText(innerRect, ttlText, style::al_center); - - constexpr auto kPenWidth = 1.5; - - const auto penWidth = style::ConvertScaleExact(kPenWidth); - auto pen = QPen(fg); - pen.setJoinStyle(Qt::RoundJoin); - pen.setCapStyle(Qt::RoundCap); - pen.setWidthF(penWidth); - - p.setPen(pen); - p.setBrush(Qt::NoBrush); - p.drawArc(innerRect, arc::kQuarterLength, arc::kHalfLength); - - p.setClipRect(innerRect - - QMarginsF(innerRect.width() / 2, -penWidth, -penWidth, -penWidth)); - pen.setStyle(Qt::DotLine); - p.setPen(pen); - p.drawEllipse(innerRect); - p.restore(); -} - [[nodiscard]] HistoryView::TtlPaintCallback CreateTtlPaintCallback( std::shared_ptr<rpl::lifetime> lifetime, Fn<void()> update) { @@ -797,7 +766,15 @@ void Document::draw( _animation->radial.draw(q, rinner, st::msgFileRadialLine, stm->historyFileRadialFg); } if (hasTtlBadge) { - DrawCornerBadgeTTL(q, stm->historyFileRadialFg->c, ttlRect); + { + auto hq = PainterHighQualityEnabler(q); + auto pen = stm->msgBg->p; + pen.setWidthF(style::ConvertScaleExact(1.5)); + q.setPen(pen); + q.setBrush(Qt::NoBrush); + q.drawEllipse(ttlRect); + } + stm->historyVoiceMessageTTL.paintInCenter(q, ttlRect); } }; if (_data->isSongWithCover() || !usesBubblePattern(context)) { diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 378393643..1b463cf50 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -513,6 +513,11 @@ msgWaveformSkip: 1px; msgWaveformMin: 3px; msgWaveformMax: 17px; +historyVoiceMessageInTTL: icon {{ "chat/mini_media_once", historyFileInIconFg }}; +historyVoiceMessageInTTLSelected: icon {{ "chat/mini_media_once", historyFileInIconFgSelected }}; +historyVoiceMessageOutTTL: icon {{ "chat/mini_media_once", historyFileOutIconFg }}; +historyVoiceMessageOutTTLSelected: icon {{ "chat/mini_media_once", historyFileOutIconFgSelected }}; + historyTranscribeSkip: 10px; historyTranscribeSize: size(28px, 22px); historyTranscribeRadius: 4px; diff --git a/Telegram/SourceFiles/ui/chat/chat_style.cpp b/Telegram/SourceFiles/ui/chat/chat_style.cpp index 4acf416ba..88f5ddd38 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_style.cpp @@ -536,6 +536,12 @@ ChatStyle::ChatStyle(rpl::producer<ColorIndicesCompressed> colorIndices) { &MessageImageStyle::historyPageEnlarge, st::historyPageEnlarge, st::historyPageEnlargeSelected); + make( + &MessageStyle::historyVoiceMessageTTL, + st::historyVoiceMessageInTTL, + st::historyVoiceMessageInTTLSelected, + st::historyVoiceMessageOutTTL, + st::historyVoiceMessageOutTTLSelected); updateDarkValue(); } diff --git a/Telegram/SourceFiles/ui/chat/chat_style.h b/Telegram/SourceFiles/ui/chat/chat_style.h index 11890a061..dca47f0f8 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.h +++ b/Telegram/SourceFiles/ui/chat/chat_style.h @@ -91,6 +91,7 @@ struct MessageStyle { style::icon historyTranscribeIcon = { Qt::Uninitialized }; style::icon historyTranscribeLock = { Qt::Uninitialized }; style::icon historyTranscribeHide = { Qt::Uninitialized }; + style::icon historyVoiceMessageTTL = { Qt::Uninitialized }; std::array< std::unique_ptr<Text::QuotePaintCache>, kColorPatternsCount> quoteCache; From a2c0491ae033483e99531ffda99915c44fad7a32 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 05:42:21 +0300 Subject: [PATCH 47/73] Added phrases to ttl viewer widget for video messages. --- Telegram/Resources/langs/lang.strings | 2 ++ .../chat_helpers/ttl_media_layer_widget.cpp | 24 +++++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index cec8bf36e..8c1560cd1 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1722,6 +1722,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_ttl_voice_tooltip_in" = "This voice message can only be played once."; "lng_ttl_voice_tooltip_out" = "This message will disappear once **{user}** plays it once."; "lng_ttl_voice_close_in" = "Delete and close"; +"lng_ttl_round_tooltip_in" = "This video message can only be played once."; +"lng_ttl_round_tooltip_out" = "This message will disappear once **{user}** plays it once."; "lng_profile_add_more_after_create" = "You will be able to add more members after you create the group."; "lng_profile_camera_title" = "Capture yourself"; diff --git a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp index e6a71d509..120f89f9e 100644 --- a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/ttl_media_layer_widget.h" #include "base/event_filter.h" +#include "data/data_document.h" #include "data/data_session.h" #include "editor/editor_layer_widget.h" #include "history/history.h" @@ -123,6 +124,11 @@ PreviewWrap::PreviewWrap( _style.get(), [=] { update(elementRect()); })) { + const auto isRound = _item + && _item->media() + && _item->media()->document() + && _item->media()->document()->isVideoMessage(); + std::move( theme ) | rpl::start_with_next([=](std::shared_ptr<Ui::ChatTheme> theme) { @@ -174,13 +180,17 @@ PreviewWrap::PreviewWrap( { auto text = item->out() - ? tr::lng_ttl_voice_tooltip_out( - lt_user, - rpl::single( - item->history()->peer->name() - ) | rpl::map(Ui::Text::RichLangValue), - Ui::Text::RichLangValue) - : tr::lng_ttl_voice_tooltip_in(Ui::Text::RichLangValue); + ? (isRound + ? tr::lng_ttl_round_tooltip_out + : tr::lng_ttl_voice_tooltip_out)( + lt_user, + rpl::single( + item->history()->peer->shortName() + ) | rpl::map(Ui::Text::RichLangValue), + Ui::Text::RichLangValue) + : (isRound + ? tr::lng_ttl_round_tooltip_in + : tr::lng_ttl_voice_tooltip_in)(Ui::Text::RichLangValue); const auto tooltip = Ui::CreateChild<Ui::ImportantTooltip>( this, object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>( From 46ddc7364c4548693c9bcedc30ec9e5ad771434f Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 12:43:32 +0300 Subject: [PATCH 48/73] Fixed possible crash on deleting of media message with ttl. --- .../history/view/media/history_view_document.cpp | 8 +++++--- .../history/view/media/history_view_gif.cpp | 11 +++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index f6e60f877..541e0c463 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -309,18 +309,20 @@ Document::Document( }, *lifetime); _drawTtl = CreateTtlPaintCallback(lifetime, [=] { repaint(); }); } else if (!_parent->data()->out()) { + const auto &data = &_parent->data()->history()->owner(); _parent->data()->removeFromSharedMediaIndex(); setDocumentLinks(_data, realParent, [=] { _openl = nullptr; auto lifetime = std::make_shared<rpl::lifetime>(); TTLVoiceStops(fullId) | rpl::start_with_next([=]() mutable { - const auto item = _parent->data(); if (lifetime) { base::take(lifetime)->destroy(); } - // Destroys this. - ClearMediaAsExpired(item); + if (const auto item = data->message(fullId)) { + // Destroys this. + ClearMediaAsExpired(item); + } }, *lifetime); return false; diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 6176bf050..51150dace 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -150,17 +150,20 @@ Gif::Gif( _drawTtl = CreateTtlPaintCallback([=] { repaint(); }); } const auto fullId = _realParent->fullId(); + const auto &data = &_parent->data()->history()->owner(); + const auto isOut = _parent->data()->out(); _parent->data()->removeFromSharedMediaIndex(); setDocumentLinks(_data, realParent, [=] { auto lifetime = std::make_shared<rpl::lifetime>(); TTLVoiceStops(fullId) | rpl::start_with_next([=]() mutable { - const auto item = _parent->data(); if (lifetime) { base::take(lifetime)->destroy(); } - if (!item->out()) { - // Destroys this. - ClearMediaAsExpired(item); + if (!isOut) { + if (const auto item = data->message(fullId)) { + // Destroys this. + ClearMediaAsExpired(item); + } } }, *lifetime); From ad6890e7ddc3197f14185f536c9631400e8cca76 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 12:59:04 +0300 Subject: [PATCH 49/73] Slightly improved progress radial for video messages with ttl. --- .../history/view/media/history_view_gif.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 51150dace..ca29639ec 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -582,18 +582,19 @@ void Gif::draw(Painter &p, const PaintContext &context) const { const auto value = playback->value(); if (value > 0.) { auto pen = st->historyVideoMessageProgressFg()->p; - auto was = p.pen(); + const auto was = p.pen(); pen.setWidth(st::radialLine); pen.setCapStyle(Qt::RoundCap); p.setPen(pen); p.setOpacity(st::historyVideoMessageProgressOpacity); - auto from = arc::kQuarterLength; - auto len = -qRound(arc::kFullLength * value); - auto stepInside = st::radialLine / 2; + const auto from = arc::kQuarterLength; + const auto len = std::round(arc::kFullLength + * (inTTLViewer ? (1. - value) : -value)); + const auto stepInside = st::radialLine / 2; { - PainterHighQualityEnabler hq(p); - p.drawArc(rthumb.marginsRemoved(QMargins(stepInside, stepInside, stepInside, stepInside)), from, len); + auto hq = PainterHighQualityEnabler(p); + p.drawArc(rthumb - Margins(stepInside), from, len); } p.setPen(was); From 5273fbf57b3bb2178deb4a59c3931419811b7293 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 13:36:24 +0300 Subject: [PATCH 50/73] Slightly improved progress radial for voice messages with ttl. --- .../view/media/history_view_document.cpp | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 541e0c463..2c963c344 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -186,7 +186,8 @@ void PaintWaveform( const PaintContext &context, const VoiceData *voiceData, int availableWidth, - float64 progress) { + float64 progress, + bool ttl) { const auto wf = [&]() -> const VoiceWaveform* { if (!voiceData) { return nullptr; @@ -198,11 +199,14 @@ void PaintWaveform( } return &voiceData->waveform; }(); + if (ttl) { + progress = 1. - progress; + } const auto stm = context.messageStyle(); // Rescale waveform by going in waveform.size * bar_count 1D grid. const auto active = stm->msgWaveformActive; - const auto inactive = stm->msgWaveformInactive; + const auto inactive = ttl ? stm->msgBg : stm->msgWaveformInactive; const auto wfSize = wf ? int(wf->size()) : ::Media::Player::kWaveformSamplesCount; @@ -755,8 +759,28 @@ void Document::draw( : nullptr; const auto paintContent = [&](QPainter &q) { + constexpr auto kPenWidth = 1.5; if (_drawTtl) { _drawTtl(q, inner, context.st->historyFileInIconFg()->c); + + const auto voice = Get<HistoryDocumentVoice>(); + const auto progress = (voice && voice->playback) + ? voice->playback->progress.current() + : 0.; + + if (progress > 0.) { + auto pen = stm->msgBg->p; + pen.setWidthF(style::ConvertScaleExact(kPenWidth)); + pen.setCapStyle(Qt::RoundCap); + q.setPen(pen); + + const auto from = arc::kQuarterLength; + const auto len = std::round(arc::kFullLength + * (1. - progress)); + const auto stepInside = pen.widthF() * 2; + auto hq = PainterHighQualityEnabler(q); + q.drawArc(inner - Margins(stepInside), from, len); + } } else if (previous && radialOpacity > 0. && radialOpacity < 1.) { PaintInterpolatedIcon(q, icon, *previous, radialOpacity, inner); } else { @@ -771,7 +795,7 @@ void Document::draw( { auto hq = PainterHighQualityEnabler(q); auto pen = stm->msgBg->p; - pen.setWidthF(style::ConvertScaleExact(1.5)); + pen.setWidthF(style::ConvertScaleExact(kPenWidth)); q.setPen(pen); q.setBrush(Qt::NoBrush); q.drawEllipse(ttlRect); @@ -843,11 +867,14 @@ void Document::draw( if (_transcribedRound) { FillWaveform(_data->round()); } + const auto inTTLViewer = _parent->delegate()->elementContext() + == Context::TTLViewer; PaintWaveform(p, context, _transcribedRound ? _data->round() : _data->voice(), namewidth + st::msgWaveformSkip, - progress); + progress, + inTTLViewer); p.restore(); } else if (auto named = Get<HistoryDocumentNamed>()) { p.setFont(st::semiboldFont); From f9b5789cf727561012e5bd9288bc342f43b98164 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 14:01:48 +0300 Subject: [PATCH 51/73] Fixed button position in voice record bar for ttl voice messages. --- .../controls/history_view_voice_record_bar.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index 1f812250b..093e26bd9 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -1325,6 +1325,7 @@ void VoiceRecordBar::init() { } updateTTLGeometry(TTLAnimationType::TopBottom, 1. - value); }; + _showListenAnimation.stop(); _showListenAnimation.start(std::move(callback), 0., to, duration); }, lifetime()); @@ -1456,13 +1457,18 @@ void VoiceRecordBar::setTTLFilter(FilterCallback &&callback) { } void VoiceRecordBar::initLockGeometry() { - rpl::combine( - _lock->heightValue(), - geometryValue(), - static_cast<Ui::RpWidget*>(parentWidget())->geometryValue() + const auto parent = static_cast<Ui::RpWidget*>(parentWidget()); + rpl::merge( + _lock->heightValue() | rpl::to_empty, + geometryValue() | rpl::to_empty, + parent->geometryValue() | rpl::to_empty ) | rpl::start_with_next([=] { updateLockGeometry(); }, lifetime()); + parent->geometryValue( + ) | rpl::start_with_next([=] { + updateTTLGeometry(TTLAnimationType::RightLeft, 1.); + }, lifetime()); } void VoiceRecordBar::initLevelGeometry() { From d1f4463c2a5dbe00eefc79d0bd611aa05afe2684 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 17:53:34 +0300 Subject: [PATCH 52/73] Added simple tooltip to ttl button from voice record bar. --- Telegram/Resources/langs/lang.strings | 1 + .../chat_helpers/chat_helpers.style | 6 +++ .../history_view_voice_record_bar.cpp | 45 +++++++++++++++++++ Telegram/lib_ui | 2 +- 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 8c1560cd1..1bbb82bd5 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2492,6 +2492,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_record_listen_cancel_sure" = "Are you sure you want to discard your recorded voice message?"; "lng_record_lock_discard" = "Discard"; "lng_record_hold_tip" = "Please hold the mouse button pressed to record a voice message."; +"lng_record_once_active_tooltip" = "The recipients will be able to listen to it only once."; "lng_will_be_notified" = "Members will be notified when you post"; "lng_wont_be_notified" = "Members will not be notified when you post"; "lng_willbe_history" = "Please select a chat to start messaging"; diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index 2ad067367..99f6f9900 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -1130,6 +1130,12 @@ historyRecordLockPosition: point(1px, 22px); historyRecordCancelButtonWidth: 100px; historyRecordCancelButtonFg: lightButtonFg; +historyRecordTooltip: ImportantTooltip(defaultImportantTooltip) { + padding: margins(4px, 4px, 4px, 4px); + radius: 11px; + arrow: 6px; +} + historySilentToggle: IconButton(historyBotKeyboardShow) { icon: icon {{ "chat/input_silent", historyComposeIconFg }}; iconOver: icon {{ "chat/input_silent", historyComposeIconFgOver }}; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index 093e26bd9..bc80a899a 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -31,7 +31,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/animation_value.h" #include "ui/effects/ripple_animation.h" #include "ui/text/format_values.h" +#include "ui/text/text_utilities.h" #include "ui/painter.h" +#include "ui/widgets/tooltip.h" #include "ui/rect.h" #include "styles/style_chat.h" #include "styles/style_chat_helpers.h" @@ -304,6 +306,49 @@ TTLButton::TTLButton( st::historyRecordVoiceShowDuration); }); + { + const auto tooltip = Ui::CreateChild<Ui::ImportantTooltip>( + parent.get(), + object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>( + parent.get(), + Ui::MakeNiceTooltipLabel( + parent, + tr::lng_record_once_active_tooltip( + Ui::Text::RichLangValue), + st::historyMessagesTTLLabel.minWidth, + st::ttlMediaImportantTooltipLabel), + st::defaultImportantTooltip.padding), + st::historyRecordTooltip); + geometryValue( + ) | rpl::start_with_next([=](const QRect &r) { + if (r.isEmpty()) { + return; + } + tooltip->pointAt(r, RectPart::Right, [=](QSize size) { + return QPoint( + r.left() + - size.width() + - st::defaultImportantTooltip.padding.left(), + r.top() + + r.height() + - size.height() + + st::historyRecordTooltip.padding.top()); + }); + }, tooltip->lifetime()); + tooltip->show(); + + clicks( + ) | rpl::start_with_next([=] { + const auto toggled = !Ui::AbstractButton::isDisabled(); + tooltip->toggleAnimated(toggled); + + if (toggled) { + constexpr auto kTimeout = crl::time(3000); + tooltip->hideAfter(kTimeout); + } + }, tooltip->lifetime()); + } + paintRequest( ) | rpl::start_with_next([=](const QRect &clip) { auto p = QPainter(this); diff --git a/Telegram/lib_ui b/Telegram/lib_ui index aa39793a9..08a19be80 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit aa39793a91f1186879c15c214a2671d78eab5085 +Subproject commit 08a19be802cef8ee801121906c5f0ce9d2fa65b0 From 8895e494669de733d88edc087f658e4846893d61 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 18:07:36 +0300 Subject: [PATCH 53/73] Fixed display of corner button in section with ttl button in record bar. --- Telegram/SourceFiles/history/history_widget.cpp | 3 ++- .../view/controls/history_view_compose_controls.cpp | 4 ++++ .../history/view/controls/history_view_compose_controls.h | 1 + .../view/controls/history_view_voice_record_bar.cpp | 4 ++++ .../history/view/controls/history_view_voice_record_bar.h | 1 + .../history/view/history_view_replies_section.cpp | 7 +++++-- .../history/view/history_view_scheduled_section.cpp | 6 ++++-- 7 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 97c586aed..1d518a32e 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6283,7 +6283,8 @@ std::optional<bool> HistoryWidget::cornerButtonsDownShown() { if (!_list || _firstLoadRequest) { return false; } - if (_voiceRecordBar->isLockPresent()) { + if (_voiceRecordBar->isLockPresent() + || _voiceRecordBar->isTTLButtonShown()) { return false; } if (!_history->loadedAtBottom() || _cornerButtons.replyReturn()) { diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 57cff6c0c..e8e81511e 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -2925,6 +2925,10 @@ bool ComposeControls::isLockPresent() const { return _voiceRecordBar->isLockPresent(); } +bool ComposeControls::isTTLButtonShown() const { + return _voiceRecordBar->isTTLButtonShown(); +} + rpl::producer<bool> ComposeControls::lockShowStarts() const { return _voiceRecordBar->lockShowStarts(); } diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h index 9ae515d6c..a846cd4ee 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -220,6 +220,7 @@ public: [[nodiscard]] rpl::producer<bool> lockShowStarts() const; [[nodiscard]] bool isLockPresent() const; + [[nodiscard]] bool isTTLButtonShown() const; [[nodiscard]] bool isRecording() const; [[nodiscard]] bool isRecordingPressed() const; [[nodiscard]] rpl::producer<bool> recordingActiveValue() const; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index bc80a899a..f8bd585b2 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -1838,6 +1838,10 @@ bool VoiceRecordBar::isRecordingByAnotherBar() const { return !isRecording() && ::Media::Capture::instance()->started(); } +bool VoiceRecordBar::isTTLButtonShown() const { + return !_ttlButton->isHidden(); +} + bool VoiceRecordBar::hasDuration() const { return _recordingSamples > 0; } diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h index 31c0eb30e..8b59ad5ea 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h @@ -98,6 +98,7 @@ public: [[nodiscard]] bool isListenState() const; [[nodiscard]] bool isActive() const; [[nodiscard]] bool isRecordingByAnotherBar() const; + [[nodiscard]] bool isTTLButtonShown() const; private: enum class StopType { diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 530af5fae..157a61977 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -1838,7 +1838,8 @@ bool RepliesWidget::cornerButtonsIgnoreVisibility() { } std::optional<bool> RepliesWidget::cornerButtonsDownShown() { - if (_composeControls->isLockPresent()) { + if (_composeControls->isLockPresent() + || _composeControls->isTTLButtonShown()) { return false; } const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; @@ -1851,7 +1852,9 @@ std::optional<bool> RepliesWidget::cornerButtonsDownShown() { } bool RepliesWidget::cornerButtonsUnreadMayBeShown() { - return _loaded && !_composeControls->isLockPresent(); + return _loaded + && !_composeControls->isLockPresent() + && !_composeControls->isTTLButtonShown(); } bool RepliesWidget::cornerButtonsHas(CornerButtonType type) { diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index ed57d5ee8..a086d71cb 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -843,7 +843,8 @@ bool ScheduledWidget::cornerButtonsIgnoreVisibility() { } std::optional<bool> ScheduledWidget::cornerButtonsDownShown() { - if (_composeControls->isLockPresent()) { + if (_composeControls->isLockPresent() + || _composeControls->isTTLButtonShown()) { return false; } const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; @@ -857,7 +858,8 @@ std::optional<bool> ScheduledWidget::cornerButtonsDownShown() { bool ScheduledWidget::cornerButtonsUnreadMayBeShown() { return _inner->loadedAtBottomKnown() - && !_composeControls->isLockPresent(); + && !_composeControls->isLockPresent() + && !_composeControls->isTTLButtonShown(); } bool ScheduledWidget::cornerButtonsHas(CornerButtonType type) { From cb4781360ae632819bf888cc18b2cdb42214da6a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 18:50:15 +0300 Subject: [PATCH 54/73] Added first shown tooltip to ttl button from voice record bar. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/core/core_settings.cpp | 9 +++- Telegram/SourceFiles/core/core_settings.h | 10 +++++ .../history_view_voice_record_bar.cpp | 44 +++++++++++++++---- 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 1bbb82bd5..357838992 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2492,6 +2492,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_record_listen_cancel_sure" = "Are you sure you want to discard your recorded voice message?"; "lng_record_lock_discard" = "Discard"; "lng_record_hold_tip" = "Please hold the mouse button pressed to record a voice message."; +"lng_record_once_first_tooltip" = "Tap to set this message to **Play Once**."; "lng_record_once_active_tooltip" = "The recipients will be able to listen to it only once."; "lng_will_be_notified" = "Members will be notified when you post"; "lng_wont_be_notified" = "Members will not be notified when you post"; diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp index ac4119d95..0ab441fe0 100644 --- a/Telegram/SourceFiles/core/core_settings.cpp +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -339,7 +339,8 @@ QByteArray Settings::serialize() const { << qint32(_ignoreBatterySaving.current() ? 1 : 0) << quint64(_macRoundIconDigest.value_or(0)) << qint32(_storiesClickTooltipHidden.current() ? 1 : 0) - << qint32(_recentEmojiSkip.size()); + << qint32(_recentEmojiSkip.size()) + << qint32(_ttlVoiceClickTooltipHidden.current() ? 1 : 0); for (const auto &id : _recentEmojiSkip) { stream << id; } @@ -453,6 +454,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { qint32 storiesClickTooltipHidden = _storiesClickTooltipHidden.current() ? 1 : 0; base::flat_set<QString> recentEmojiSkip; qint32 trayIconMonochrome = (_trayIconMonochrome.current() ? 1 : 0); + qint32 ttlVoiceClickTooltipHidden = _ttlVoiceClickTooltipHidden.current() ? 1 : 0; stream >> themesAccentColors; if (!stream.atEnd()) { @@ -709,6 +711,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) { // Let existing clients use the old value. trayIconMonochrome = 0; } + if (!stream.atEnd()) { + stream >> ttlVoiceClickTooltipHidden; + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for Core::Settings::constructFromSerialized()")); @@ -903,6 +908,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { _storiesClickTooltipHidden = (storiesClickTooltipHidden == 1); _recentEmojiSkip = std::move(recentEmojiSkip); _trayIconMonochrome = (trayIconMonochrome == 1); + _ttlVoiceClickTooltipHidden = (ttlVoiceClickTooltipHidden == 1); } QString Settings::getSoundPath(const QString &key) const { @@ -1259,6 +1265,7 @@ void Settings::resetOnLastLogout() { _systemDarkModeEnabled = false; _hiddenGroupCallTooltips = 0; _storiesClickTooltipHidden = false; + _ttlVoiceClickTooltipHidden = false; _recentEmojiPreload.clear(); _recentEmoji.clear(); diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index 0f7082293..5afab71f9 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -820,6 +820,15 @@ public: void setStoriesClickTooltipHidden(bool value) { _storiesClickTooltipHidden = value; } + [[nodiscard]] bool ttlVoiceClickTooltipHidden() const { + return _ttlVoiceClickTooltipHidden.current(); + } + [[nodiscard]] rpl::producer<bool> ttlVoiceClickTooltipHiddenValue() const { + return _ttlVoiceClickTooltipHidden.value(); + } + void setTtlVoiceClickTooltipHidden(bool value) { + _ttlVoiceClickTooltipHidden = value; + } [[nodiscard]] static bool ThirdColumnByDefault(); [[nodiscard]] static float64 DefaultDialogsWidthRatio(); @@ -945,6 +954,7 @@ private: rpl::variable<bool> _ignoreBatterySaving = false; std::optional<uint64> _macRoundIconDigest; rpl::variable<bool> _storiesClickTooltipHidden = false; + rpl::variable<bool> _ttlVoiceClickTooltipHidden = false; bool _tabbedReplacedWithInfo = false; // per-window rpl::event_stream<bool> _tabbedReplacedWithInfoValue; // per-window diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index f8bd585b2..d78bc4b41 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -280,7 +280,6 @@ protected: private: const style::RecordBar &_st; const QRect _rippleRect; - const QString _text; Ui::Animations::Simple _activeAnimation; @@ -292,8 +291,7 @@ TTLButton::TTLButton( : RippleButton(parent, st.lock.ripple) , _st(st) , _rippleRect(Rect(Size(st::historyRecordLockTopShadow.width())) - - (st::historyRecordLockRippleMargin)) -, _text(u"1"_q) { + - (st::historyRecordLockRippleMargin)) { resize(Size(st::historyRecordLockTopShadow.width())); setClickedCallback([=] { @@ -306,20 +304,27 @@ TTLButton::TTLButton( st::historyRecordVoiceShowDuration); }); - { + Ui::RpWidget::shownValue() | rpl::filter( + rpl::mappers::_1 + ) | rpl::skip(1) | rpl::take(1) | rpl::start_with_next([=] { + auto text = rpl::conditional( + Core::App().settings().ttlVoiceClickTooltipHiddenValue(), + tr::lng_record_once_active_tooltip( + Ui::Text::RichLangValue), + tr::lng_record_once_first_tooltip( + Ui::Text::RichLangValue)); const auto tooltip = Ui::CreateChild<Ui::ImportantTooltip>( parent.get(), object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>( parent.get(), Ui::MakeNiceTooltipLabel( parent, - tr::lng_record_once_active_tooltip( - Ui::Text::RichLangValue), + std::move(text), st::historyMessagesTTLLabel.minWidth, st::ttlMediaImportantTooltipLabel), st::defaultImportantTooltip.padding), st::historyRecordTooltip); - geometryValue( + Ui::RpWidget::geometryValue( ) | rpl::start_with_next([=](const QRect &r) { if (r.isEmpty()) { return; @@ -336,6 +341,15 @@ TTLButton::TTLButton( }); }, tooltip->lifetime()); tooltip->show(); + if (!Core::App().settings().ttlVoiceClickTooltipHidden()) { + clicks( + ) | rpl::take(1) | rpl::start_with_next([=] { + Core::App().settings().setTtlVoiceClickTooltipHidden(true); + }, tooltip->lifetime()); + tooltip->toggleAnimated(true); + } else { + tooltip->toggleFast(false); + } clicks( ) | rpl::start_with_next([=] { @@ -347,7 +361,19 @@ TTLButton::TTLButton( tooltip->hideAfter(kTimeout); } }, tooltip->lifetime()); - } + + Ui::RpWidget::geometryValue( + ) | rpl::map([=](const QRect &r) { + return (r.left() + r.width() > parentWidget()->width()); + }) | rpl::distinct_until_changed( + ) | rpl::start_with_next([=](bool toHide) { + const auto isFirstTooltip = + !Core::App().settings().ttlVoiceClickTooltipHidden(); + if (isFirstTooltip || (!isFirstTooltip && toHide)) { + tooltip->toggleAnimated(!toHide); + } + }, tooltip->lifetime()); + }, lifetime()); paintRequest( ) | rpl::start_with_next([=](const QRect &clip) { @@ -1633,6 +1659,8 @@ void VoiceRecordBar::finish() { _listen = nullptr; + [[maybe_unused]] const auto s = takeTTLState(); + _sendActionUpdates.fire({ Api::SendProgressType::RecordVoice, -1 }); } From b462d7627fe4adfacefb0f0d71415e2c09b2a46e Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 08:35:38 +0400 Subject: [PATCH 55/73] Fix channels in poll results restoring. --- .../info/polls/info_polls_results_inner_widget.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp b/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp index b1cefdeff..3d42cb8c0 100644 --- a/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp +++ b/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp @@ -372,10 +372,7 @@ void ListController::restoreState(std::unique_ptr<PeerListState> state) { std::unique_ptr<PeerListRow> ListController::createRestoredRow( not_null<PeerData*> peer) { - if (const auto user = peer->asUser()) { - return createRow(user); - } - return nullptr; + return createRow(peer); } void ListController::rowClicked(not_null<PeerListRow*> row) { From 104cf504ab4349c971f30a23e6ee4692abb1dc24 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 10:34:49 +0400 Subject: [PATCH 56/73] Play ttl media horizontally where the message was. --- .../chat_helpers/ttl_media_layer_widget.cpp | 135 ++++++++++++------ .../history/view/history_view_message.cpp | 4 +- .../view/media/history_view_document.cpp | 10 +- 3 files changed, 99 insertions(+), 50 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp index 120f89f9e..817cd4709 100644 --- a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp @@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/tooltip.h" #include "window/section_widget.h" // Window::ChatThemeValueFromPeer. #include "window/themes/window_theme.h" +#include "window/window_controller.h" #include "window/window_session_controller.h" #include "styles/style_chat.h" #include "styles/style_chat_helpers.h" @@ -44,6 +45,7 @@ public: PreviewDelegate( not_null<QWidget*> parent, not_null<Ui::ChatStyle*> st, + rpl::producer<bool> chatWideValue, Fn<void()> update); bool elementAnimationsPaused() override; @@ -54,15 +56,18 @@ public: private: const not_null<QWidget*> _parent; const std::unique_ptr<Ui::PathShiftGradient> _pathGradient; + rpl::variable<bool> _chatWide; }; PreviewDelegate::PreviewDelegate( not_null<QWidget*> parent, not_null<Ui::ChatStyle*> st, + rpl::producer<bool> chatWideValue, Fn<void()> update) : _parent(parent) -, _pathGradient(HistoryView::MakePathShiftGradient(st, update)) { +, _pathGradient(HistoryView::MakePathShiftGradient(st, update)) +, _chatWide(std::move(chatWideValue)) { } bool PreviewDelegate::elementAnimationsPaused() { @@ -78,7 +83,7 @@ HistoryView::Context PreviewDelegate::elementContext() { } bool PreviewDelegate::elementIsChatWide() { - return true; + return _chatWide.current(); } class PreviewWrap final : public Ui::RpWidget { @@ -86,6 +91,8 @@ public: PreviewWrap( not_null<Ui::RpWidget*> parent, not_null<HistoryItem*> item, + rpl::producer<QRect> viewportValue, + rpl::producer<bool> chatWideValue, rpl::producer<std::shared_ptr<Ui::ChatTheme>> theme); ~PreviewWrap(); @@ -93,13 +100,17 @@ public: private: void paintEvent(QPaintEvent *e) override; - [[nodiscard]] QRect elementRect() const; const not_null<HistoryItem*> _item; const std::unique_ptr<Ui::ChatStyle> _style; const std::unique_ptr<PreviewDelegate> _delegate; + rpl::variable<QRect> _globalViewport; + rpl::variable<bool> _chatWide; std::shared_ptr<Ui::ChatTheme> _theme; std::unique_ptr<HistoryView::Element> _element; + QRect _viewport; + QRect _elementGeometry; + rpl::variable<QRect> _elementInner; rpl::lifetime _elementLifetime; struct { @@ -114,6 +125,8 @@ private: PreviewWrap::PreviewWrap( not_null<Ui::RpWidget*> parent, not_null<HistoryItem*> item, + rpl::producer<QRect> viewportValue, + rpl::producer<bool> chatWideValue, rpl::producer<std::shared_ptr<Ui::ChatTheme>> theme) : RpWidget(parent) , _item(item) @@ -122,8 +135,9 @@ PreviewWrap::PreviewWrap( , _delegate(std::make_unique<PreviewDelegate>( parent, _style.get(), - [=] { update(elementRect()); })) { - + std::move(chatWideValue), + [=] { update(_elementGeometry); })) +, _globalViewport(std::move(viewportValue)) { const auto isRound = _item && _item->media() && _item->media()->document() @@ -140,7 +154,7 @@ PreviewWrap::PreviewWrap( session->data().viewRepaintRequest( ) | rpl::start_with_next([=](not_null<const HistoryView::Element*> view) { if (view == _element.get()) { - update(elementRect()); + update(_elementGeometry); } }, lifetime()); @@ -157,11 +171,15 @@ PreviewWrap::PreviewWrap( close->setClickedCallback(closeCallback); close->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); - sizeValue( - ) | rpl::start_with_next([=](const QSize &s) { + rpl::combine( + sizeValue(), + _elementInner.value() + ) | rpl::start_with_next([=](QSize size, QRect inner) { close->moveToLeft( - (s.width() - close->width()) / 2, - s.height() - close->height() - st::ttlMediaButtonBottomSkip); + inner.x() + (inner.width() - close->width()) / 2, + (size.height() + - close->height() + - st::ttlMediaButtonBottomSkip)); }, close->lifetime()); } @@ -170,11 +188,27 @@ PreviewWrap::PreviewWrap( { _element->initDimensions(); - widthValue( - ) | rpl::filter([=](int width) { - return width > st::msgMinWidth; - }) | rpl::start_with_next([=](int width) { - _element->resizeGetHeight(width); + rpl::combine( + sizeValue(), + _globalViewport.value() + ) | rpl::start_with_next([=](QSize outer, QRect globalViewport) { + _viewport = globalViewport.isEmpty() + ? rect() + : mapFromGlobal(globalViewport); + if (_viewport.width() < st::msgMinWidth) { + return; + } + _element->resizeGetHeight(_viewport.width()); + _elementGeometry = QRect( + (_viewport.width() - _element->width()) / 2, + (_viewport.height() - _element->height()) / 2, + _element->width(), + _element->height() + ).translated(_viewport.topLeft()); + const auto media = _element->media(); + _elementInner = _element->innerGeometry().translated( + _elementGeometry.topLeft()); + update(); }, _elementLifetime); } @@ -203,22 +237,17 @@ PreviewWrap::PreviewWrap( st::defaultImportantTooltip.padding), st::dialogsStoriesTooltip); tooltip->toggleFast(true); - sizeValue( - ) | rpl::filter( - [](const QSize &s) { return !s.isNull(); } - ) | rpl::take(1) | rpl::start_with_next([=](const QSize &s) { - if (s.isEmpty()) { - return; - } - auto area = elementRect(); - area.setWidth(_element->media() - ? _element->media()->width() - : _element->width()); - tooltip->pointAt(area, RectPart::Top, [=](QSize size) { + _elementInner.value( + ) | rpl::filter([](const QRect &inner) { + return !inner.isEmpty(); + }) | rpl::start_with_next([=](const QRect &inner) { + tooltip->pointAt(inner, RectPart::Top, [=](QSize size) { return QPoint{ - (area.width() - size.width()) / 2, - (s.height() - size.height() * 2 - _element->height()) / 2 - - st::defaultImportantTooltip.padding.top(), + inner.x() + (inner.width() - size.width()) / 2, + (inner.y() + - st::normalFont->height + - size.height() + - st::defaultImportantTooltip.padding.top()), }; }); }, tooltip->lifetime()); @@ -232,14 +261,6 @@ PreviewWrap::PreviewWrap( }, lifetime()); } -QRect PreviewWrap::elementRect() const { - return QRect( - (width() - _element->width()) / 2, - (height() - _element->height()) / 2, - _element->width(), - _element->height()); -} - rpl::producer<> PreviewWrap::closeRequests() const { return _closeRequests.events(); } @@ -250,13 +271,14 @@ PreviewWrap::~PreviewWrap() { } void PreviewWrap::paintEvent(QPaintEvent *e) { - if (!_element) { + if (!_element || _elementGeometry.isEmpty()) { return; } auto p = QPainter(this); - const auto r = rect(); - + //p.fillRect(_viewport, QColor(255, 0, 0, 64)); + //p.fillRect(_elementGeometry, QColor(0, 255, 0, 64)); + //p.fillRect(_elementInner.current(), QColor(0, 0, 255, 64)); if (!_last.use) { const auto size = _element->currentSize(); auto result = QImage( @@ -276,12 +298,35 @@ void PreviewWrap::paintEvent(QPaintEvent *e) { } _last.frame = std::move(result); } - p.translate( - (r.width() - _element->width()) / 2, - (r.height() - _element->height()) / 2); + p.translate(_elementGeometry.topLeft()); p.drawImage(0, 0, _last.frame); } +rpl::producer<QRect> GlobalViewportForWindow( + not_null<Window::SessionController*> controller) { + const auto delegate = controller->window().floatPlayerDelegate(); + return rpl::single(rpl::empty) | rpl::then( + delegate->floatPlayerAreaUpdates() + ) | rpl::map([=] { + auto section = (Media::Player::FloatSectionDelegate*)nullptr; + delegate->floatPlayerEnumerateSections([&]( + not_null<Media::Player::FloatSectionDelegate*> check, + Window::Column column) { + if ((column == Window::Column::First && !section) + || column == Window::Column::Second) { + section = check; + } + }); + if (section) { + const auto rect = section->floatPlayerAvailableRect(); + if (rect.width() >= st::msgMinWidth) { + return rect; + } + } + return QRect(); + }); +} + } // namespace void ShowTTLMediaLayerWidget( @@ -292,6 +337,8 @@ void ShowTTLMediaLayerWidget( auto preview = base::make_unique_q<PreviewWrap>( parent, item, + GlobalViewportForWindow(controller), + controller->adaptive().chatWideValue(), Window::ChatThemeValueFromPeer( controller, item->history()->peer)); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index d7c9e2f16..93db9cd12 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1984,6 +1984,7 @@ bool Message::hasFromPhoto() const { case Context::AdminLog: return true; case Context::History: + case Context::TTLViewer: case Context::Pinned: case Context::Replies: case Context::SavedSublist: { @@ -2005,7 +2006,6 @@ bool Message::hasFromPhoto() const { return !item->out() && !item->history()->peer->isUser(); } break; case Context::ContactPreview: - case Context::TTLViewer: return false; } Unexpected("Context in Message::hasFromPhoto."); @@ -3171,6 +3171,7 @@ bool Message::hasFromName() const { case Context::AdminLog: return true; case Context::History: + case Context::TTLViewer: case Context::Pinned: case Context::Replies: case Context::SavedSublist: { @@ -3201,7 +3202,6 @@ bool Message::hasFromName() const { return false; } break; case Context::ContactPreview: - case Context::TTLViewer: return false; } Unexpected("Context in Message::hasFromName."); diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 2c963c344..5c3632c33 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -243,10 +243,12 @@ void PaintWaveform( p.fillRect( QRectF(barLeft, barTop, leftWidth, barHeight), active); - p.fillRect( - QRectF(activeWidth, barTop, rightWidth, barHeight), - inactive); - } else { + if (!ttl) { + p.fillRect( + QRectF(activeWidth, barTop, rightWidth, barHeight), + inactive); + } + } else if (!ttl || barLeft < activeWidth) { const auto &color = (barLeft >= activeWidth) ? inactive : active; p.fillRect(QRectF(barLeft, barTop, barWidth, barHeight), color); } From b31bb6dd3373f38232feb627c860372ba901bde2 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 10:53:26 +0400 Subject: [PATCH 57/73] Fix sending single-time voice messages. --- .../controls/history_view_voice_record_bar.cpp | 14 ++++++++++---- .../view/controls/history_view_voice_record_bar.h | 3 ++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index d78bc4b41..3714bbf8f 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -1638,10 +1638,12 @@ void VoiceRecordBar::stop(bool send) { if (isHidden() && !send) { return; } + const auto ttlBeforeHide = peekTTLState(); auto disappearanceCallback = [=] { hide(); - stopRecording(send ? StopType::Send : StopType::Cancel); + const auto type = send ? StopType::Send : StopType::Cancel; + stopRecording(type, ttlBeforeHide); }; _lockShowing = false; visibilityAnimate(false, std::move(disappearanceCallback)); @@ -1671,7 +1673,7 @@ void VoiceRecordBar::hideFast() { [[maybe_unused]] const auto s = takeTTLState(); } -void VoiceRecordBar::stopRecording(StopType type) { +void VoiceRecordBar::stopRecording(StopType type, bool ttlBeforeHide) { using namespace ::Media::Capture; if (type == StopType::Cancel) { instance()->stop(crl::guard(this, [=](Result &&data) { @@ -1691,9 +1693,9 @@ void VoiceRecordBar::stopRecording(StopType type) { const auto duration = Duration(data.samples); if (type == StopType::Send) { const auto options = Api::SendOptions{ - .ttlSeconds = takeTTLState() + .ttlSeconds = (ttlBeforeHide ? std::numeric_limits<int>::max() - : 0 + : 0), }; _sendVoiceRequests.fire({ data.bytes, @@ -1901,6 +1903,10 @@ void VoiceRecordBar::computeAndSetLockProgress(QPoint globalPos) { _lock->requestPaintProgress(Progress(localPos.y(), higher - lower)); } +bool VoiceRecordBar::peekTTLState() const { + return !_ttlButton->isDisabled(); +} + bool VoiceRecordBar::takeTTLState() const { const auto hasTtl = !_ttlButton->isDisabled(); _ttlButton->clearState(); diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h index 8b59ad5ea..964614597 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h @@ -126,7 +126,7 @@ private: [[nodiscard]] bool recordingAnimationCallback(crl::time now); void stop(bool send); - void stopRecording(StopType type); + void stopRecording(StopType type, bool ttlBeforeHide = false); void visibilityAnimate(bool show, Fn<void()> &&callback); [[nodiscard]] bool showRecordButton() const; @@ -149,6 +149,7 @@ private: void computeAndSetLockProgress(QPoint globalPos); + [[nodiscard]] bool peekTTLState() const; [[nodiscard]] bool takeTTLState() const; const style::RecordBar &_st; From 6b910e11e5ee7d9cafc1d83c185a2d6ceb267f64 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 11:16:58 +0400 Subject: [PATCH 58/73] Update lib_webview submodle. --- Telegram/lib_webview | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/lib_webview b/Telegram/lib_webview index a1c84d636..d7da1570f 160000 --- a/Telegram/lib_webview +++ b/Telegram/lib_webview @@ -1 +1 @@ -Subproject commit a1c84d636f7975781dece08939bbc24da8298c3c +Subproject commit d7da1570f02485d9bdcd929cd2ce5845b52f5178 From 6f64fea0b129d077a1e9a87240ac53099167b201 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 11:20:41 +0400 Subject: [PATCH 59/73] Fix build with Xcode. --- Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp | 2 +- Telegram/SourceFiles/dialogs/dialogs_widget.cpp | 6 ++++++ Telegram/SourceFiles/dialogs/dialogs_widget.h | 7 +++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 05e54ec6b..14c9552bb 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -1781,7 +1781,7 @@ void InnerWidget::mousePressReleased( } } if (auto activated = ClickHandler::unpressed()) { - ActivateClickHandler(window(), activated, { button }); + ActivateClickHandler(window(), activated, ClickContext{ button }); } } diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index b41257487..b6f0d414b 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -2691,6 +2691,12 @@ bool Widget::setSearchInChat( return true; } +bool Widget::setSearchInChat( + Key chat, + PeerData *from) { + return setSearchInChat(chat, from, {}); +} + void Widget::clearSearchCache() { _searchCache.clear(); _singleMessageSearch.clear(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 3c8373cb1..fc7264376 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -182,8 +182,11 @@ private: [[nodiscard]] bool searchForTopicsRequired(const QString &query) const; bool setSearchInChat( Key chat, - PeerData *from = nullptr, - std::vector<Data::ReactionId> tags = {}); + PeerData *from, + std::vector<Data::ReactionId> tags); + bool setSearchInChat( + Key chat, + PeerData *from = nullptr); void showCalendar(); void showSearchFrom(); void showMainMenu(); From 93a734eecf3f73e2a18ee7caeb47ef01c5f890b4 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 11:56:08 +0400 Subject: [PATCH 60/73] Prepare ttl-media release. --- Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp | 4 +++- Telegram/SourceFiles/history/history_item.cpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 14c9552bb..cea479bb4 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -2986,7 +2986,9 @@ void InnerWidget::searchInChat( if (peer->isSelf()) { const auto reactions = &peer->owner().reactions(); const auto list = [=] { - return reactions->list(Data::Reactions::Type::MyTags); + // Disable reactions as tags for now. + //return reactions->list(Data::Reactions::Type::MyTags); + return std::vector<Data::Reaction>(); }; _searchTags = std::make_unique<SearchTags>( &peer->owner(), diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 35a2dc7db..bf473a19b 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -2430,7 +2430,8 @@ const std::vector<Data::MessageReaction> &HistoryItem::reactions() const { } bool HistoryItem::reactionsAreTags() const { - return _flags & MessageFlag::ReactionsAreTags; + // Disable reactions as tags for now. + return false;// _flags & MessageFlag::ReactionsAreTags; } auto HistoryItem::recentReactions() const From 06775b5623970e389cf37fd1b0e39b2deaf8ebd3 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 11:56:28 +0400 Subject: [PATCH 61/73] Optimize ttl media overlay a bit. --- .../chat_helpers/ttl_media_layer_widget.cpp | 58 +++++++------------ .../view/media/history_view_document.cpp | 9 ++- 2 files changed, 28 insertions(+), 39 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp index 817cd4709..552b050e0 100644 --- a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp @@ -113,10 +113,7 @@ private: rpl::variable<QRect> _elementInner; rpl::lifetime _elementLifetime; - struct { - QImage frame; - bool use = false; - } _last; + QImage _lastFrameCache; rpl::event_stream<> _closeRequests; @@ -138,6 +135,14 @@ PreviewWrap::PreviewWrap( std::move(chatWideValue), [=] { update(_elementGeometry); })) , _globalViewport(std::move(viewportValue)) { + const auto closeCallback = [=] { _closeRequests.fire({}); }; + HistoryView::TTLVoiceStops( + item->fullId() + ) | rpl::start_with_next([=] { + _lastFrameCache = Ui::GrabWidgetToImage(this, _elementGeometry); + closeCallback(); + }, lifetime()); + const auto isRound = _item && _item->media() && _item->media()->document() @@ -158,8 +163,6 @@ PreviewWrap::PreviewWrap( } }, lifetime()); - const auto closeCallback = [=] { _closeRequests.fire({}); }; - { const auto close = Ui::CreateChild<Ui::RoundButton>( this, @@ -252,13 +255,6 @@ PreviewWrap::PreviewWrap( }); }, tooltip->lifetime()); } - - HistoryView::TTLVoiceStops( - item->fullId() - ) | rpl::start_with_next([=] { - _last.use = true; - closeCallback(); - }, lifetime()); } rpl::producer<> PreviewWrap::closeRequests() const { @@ -275,31 +271,19 @@ void PreviewWrap::paintEvent(QPaintEvent *e) { return; } - auto p = QPainter(this); - //p.fillRect(_viewport, QColor(255, 0, 0, 64)); - //p.fillRect(_elementGeometry, QColor(0, 255, 0, 64)); - //p.fillRect(_elementInner.current(), QColor(0, 0, 255, 64)); - if (!_last.use) { - const auto size = _element->currentSize(); - auto result = QImage( - size * style::DevicePixelRatio(), - QImage::Format_ARGB32_Premultiplied); - result.fill(Qt::transparent); - result.setDevicePixelRatio(style::DevicePixelRatio()); - { - auto q = Painter(&result); - auto context = _theme->preparePaintContext( - _style.get(), - Rect(size), - Rect(size), - !window()->isActiveWindow()); - context.outbg = _element->hasOutLayout(); - _element->draw(q, context); - } - _last.frame = std::move(result); - } + auto p = Painter(this); p.translate(_elementGeometry.topLeft()); - p.drawImage(0, 0, _last.frame); + if (!_lastFrameCache.isNull()) { + p.drawImage(0, 0, _lastFrameCache); + } else { + auto context = _theme->preparePaintContext( + _style.get(), + Rect(_element->currentSize()), + Rect(_element->currentSize()), + !window()->isActiveWindow()); + context.outbg = _element->hasOutLayout(); + _element->draw(p, context); + } } rpl::producer<QRect> GlobalViewportForWindow( diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 5c3632c33..3eb378a17 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -71,8 +71,13 @@ constexpr auto kAudioVoiceMsgUpdateView = crl::time(100); st::historyFileInPause.width(), st::historyFileInPause.height())); const auto state = lifetime->make_state<State>(); - state->start = Lottie::MakeIcon({ - .name = u"voice_ttl_start"_q, + //state->start = Lottie::MakeIcon({ + // .name = u"voice_ttl_start"_q, + // .color = &st::historyFileInIconFg, + // .sizeOverride = iconSize, + //}); + state->idle = Lottie::MakeIcon({ + .name = u"voice_ttl_idle"_q, .color = &st::historyFileInIconFg, .sizeOverride = iconSize, }); From 6033071e61ecb98818a0524eb71f9272b244d146 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 12:53:23 +0400 Subject: [PATCH 62/73] Fix new taskbar "Quit Telegram" icon generation. --- Telegram/SourceFiles/platform/win/tray_win.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Telegram/SourceFiles/platform/win/tray_win.cpp b/Telegram/SourceFiles/platform/win/tray_win.cpp index 2a8e4615e..d2fa0af69 100644 --- a/Telegram/SourceFiles/platform/win/tray_win.cpp +++ b/Telegram/SourceFiles/platform/win/tray_win.cpp @@ -410,6 +410,8 @@ void WriteIco(const QString &path, std::vector<QImage> images) { buffer.append(pngs[i]); } + const auto dir = QFileInfo(path).dir(); + dir.mkpath(dir.absolutePath()); auto f = QFile(path); if (f.open(QIODevice::WriteOnly)) { f.write(buffer); From 3301d28615624463baa1243427503c22e76dfbe8 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 12:53:50 +0400 Subject: [PATCH 63/73] Fix white glitch workaround on Windows. --- Telegram/lib_ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 08a19be80..564e354c1 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 08a19be802cef8ee801121906c5f0ce9d2fa65b0 +Subproject commit 564e354c1d4fabe906cb790babe6879e33faca54 From ac7958f33503d796e02ba5e364e5a04d762e73fa Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 13:03:44 +0400 Subject: [PATCH 64/73] Remove ctrl+shift+N shortcuts by default. Those are used in some input methods, including Farsi. You can always add such bindings in tdata/shortcuts-custom.json for the "account1", "account2", etc commands. Fixes #27334. --- Telegram/SourceFiles/core/shortcuts.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/core/shortcuts.cpp b/Telegram/SourceFiles/core/shortcuts.cpp index ad4a79eb7..b2190393a 100644 --- a/Telegram/SourceFiles/core/shortcuts.cpp +++ b/Telegram/SourceFiles/core/shortcuts.cpp @@ -410,9 +410,9 @@ void Manager::fillDefaults() { kShowAccount, ranges::views::ints(1, ranges::unreachable)); - for (const auto &[command, index] : accounts) { - set(u"%1+shift+%2"_q.arg(ctrl).arg(index), command); - } + //for (const auto &[command, index] : accounts) { + // set(u"%1+shift+%2"_q.arg(ctrl).arg(index), command); + //} set(u"%1+shift+down"_q.arg(ctrl), Command::FolderNext); set(u"%1+shift+up"_q.arg(ctrl), Command::FolderPrevious); @@ -458,6 +458,18 @@ void Manager::writeDefaultFile() { } } + // Commands without a default value. + for (const auto command : kShowAccount) { + const auto j = CommandNames.find(command); + if (j != CommandNames.end()) { + QJsonObject entry; + entry.insert(u"keys"_q, QJsonValue()); + entry.insert(u"command"_q, j->second); + shortcuts.append(entry); + } + } + + auto document = QJsonDocument(); document.setArray(shortcuts); file.write(document.toJson(QJsonDocument::Indented)); From 2213bedc12c47952e6d5812d738c2ac07c69bb38 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 13:14:36 +0400 Subject: [PATCH 65/73] Version 4.14.5. - Allow sending one-time voice messages. - Improve playing one-time voice and video messages. - Remove Ctrl+Shift+[1-6] shortcuts by default, some are used in input methods. - Some bugs and glitches fixed. --- 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 | 7 +++++++ 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 8030e5cba..607a27620 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ <Identity Name="TelegramMessengerLLP.TelegramDesktop" ProcessorArchitecture="ARCHITECTURE" Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A" - Version="4.14.4.0" /> + Version="4.14.5.0" /> <Properties> <DisplayName>Telegram Desktop</DisplayName> <PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName> diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 158616895..ffa88efad 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 4,14,4,0 - PRODUCTVERSION 4,14,4,0 + FILEVERSION 4,14,5,0 + PRODUCTVERSION 4,14,5,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "4.14.4.0" + VALUE "FileVersion", "4.14.5.0" VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.14.4.0" + VALUE "ProductVersion", "4.14.5.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index bfc6ab89c..3c128e7a5 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 4,14,4,0 - PRODUCTVERSION 4,14,4,0 + FILEVERSION 4,14,5,0 + PRODUCTVERSION 4,14,5,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", "4.14.4.0" + VALUE "FileVersion", "4.14.5.0" VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.14.4.0" + VALUE "ProductVersion", "4.14.5.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index d6e18ed78..44cb36e25 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 = 4014004; -constexpr auto AppVersionStr = "4.14.4"; +constexpr auto AppVersion = 4014005; +constexpr auto AppVersionStr = "4.14.5"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 7f191e54d..35cc3ece4 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 4014004 +AppVersion 4014005 AppVersionStrMajor 4.14 -AppVersionStrSmall 4.14.4 -AppVersionStr 4.14.4 +AppVersionStrSmall 4.14.5 +AppVersionStr 4.14.5 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 4.14.4 +AppVersionOriginal 4.14.5 diff --git a/changelog.txt b/changelog.txt index 06857dfac..6c316d6e1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,10 @@ +4.14.5 (15.01.24) + +- Allow sending one-time voice messages. +- Improve playing one-time voice and video messages. +- Remove Ctrl+Shift+[1-6] shortcuts by default, some are used in input methods. +- Some bugs and glitches fixed. + 4.14.4 (08.01.24) - Switch between logged in accounts using Ctrl+Shift+[1-6] shortcuts. From ed027c23d0bafccfdb33c4283c43e4dc6e0700f8 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 20:29:37 +0400 Subject: [PATCH 66/73] Version 4.14.5: Fix build with GCC. --- .../SourceFiles/chat_helpers/ttl_media_layer_widget.cpp | 1 - Telegram/SourceFiles/core/shortcuts.cpp | 6 +++--- Telegram/SourceFiles/dialogs/dialogs_widget.cpp | 2 -- Telegram/SourceFiles/history/history_inner_widget.cpp | 2 -- .../SourceFiles/history/view/media/history_view_gif.cpp | 4 ---- .../history/view/reactions/history_view_reactions.cpp | 1 - 6 files changed, 3 insertions(+), 13 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp index 552b050e0..fae8f0c2d 100644 --- a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp @@ -208,7 +208,6 @@ PreviewWrap::PreviewWrap( _element->width(), _element->height() ).translated(_viewport.topLeft()); - const auto media = _element->media(); _elementInner = _element->innerGeometry().translated( _elementGeometry.topLeft()); update(); diff --git a/Telegram/SourceFiles/core/shortcuts.cpp b/Telegram/SourceFiles/core/shortcuts.cpp index b2190393a..545c9b55a 100644 --- a/Telegram/SourceFiles/core/shortcuts.cpp +++ b/Telegram/SourceFiles/core/shortcuts.cpp @@ -406,9 +406,9 @@ void Manager::fillDefaults() { set(u"%1+%2"_q.arg(ctrl).arg(index), command); } - auto &&accounts = ranges::views::zip( - kShowAccount, - ranges::views::ints(1, ranges::unreachable)); + //auto &&accounts = ranges::views::zip( + // kShowAccount, + // ranges::views::ints(1, ranges::unreachable)); //for (const auto &[command, index] : accounts) { // set(u"%1+shift+%2"_q.arg(ctrl).arg(index), command); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index b6f0d414b..9f2c9290c 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1935,7 +1935,6 @@ void Widget::searchMessages(QString query, Key inChat) { const auto inChatChanged = [&] { const auto inPeer = inChat.peer(); const auto inTopic = inChat.topic(); - const auto inSublist = inChat.sublist(); if (!inTopic && _openedForum && inPeer == _openedForum->channel() @@ -2615,7 +2614,6 @@ bool Widget::setSearchInChat( } const auto peer = chat.peer(); const auto topic = chat.topic(); - const auto sublist = chat.sublist(); const auto forum = peer ? peer->forum() : nullptr; if (chat.folder() || (forum && !topic)) { chat = Key(); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 9cf3ab373..17fb3257b 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -981,8 +981,6 @@ Ui::ChatPaintContext HistoryInner::preparePaintContext( const QRect &clip) const { const auto visibleAreaPositionGlobal = mapToGlobal( QPoint(0, _visibleAreaTop)); - const auto visibleAreaPositionLocal = mapFromGlobal( - visibleAreaPositionGlobal); return _controller->preparePaintContext({ .theme = _theme.get(), .clip = clip, diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index ca29639ec..03164193b 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -71,9 +71,6 @@ int gifMaxStatusWidth(DocumentData *document) { [[nodiscard]] HistoryView::TtlRoundPaintCallback CreateTtlPaintCallback( Fn<void()> update) { - const auto iconSize = Size(std::min( - st::historyFileInPause.width(), - st::historyFileInPause.height())); const auto centerMargins = Margins(st::historyFileInPause.width() * 3); const auto renderer = std::make_shared<QSvgRenderer>( @@ -144,7 +141,6 @@ Gif::Gif( ? std::make_unique<MediaSpoiler>() : nullptr) , _downloadSize(Ui::FormatSizeText(_data->size)) { - auto hasDefaultDocumentLinks = false; if (_data->isVideoMessage() && _parent->data()->media()->ttlSeconds()) { if (_spoiler) { _drawTtl = CreateTtlPaintCallback([=] { repaint(); }); diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp index 292774899..39ae8087a 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp @@ -408,7 +408,6 @@ void InlineList::paint( : st->msgServiceBg())->c; } - const auto radius = geometry.height() / 2.; const auto fill = geometry.marginsAdded({ flipped ? bubbleSkip : 0, 0, From 6686fe110d586f30a8668dc6e4a1861860a1bde3 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 20:29:58 +0400 Subject: [PATCH 67/73] Fix release script working from Linux. --- Telegram/build/release.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Telegram/build/release.py b/Telegram/build/release.py index d7bee5077..4bcf93fe9 100644 --- a/Telegram/build/release.py +++ b/Telegram/build/release.py @@ -88,7 +88,8 @@ def appendSubmodules(appendTo, root, rootRevision): return False if not appendSubmodules(tmppath, subroot, revision): return False - if not invoke('gtar --concatenate --file=' + appendTo + '.tar ' + tmppath + '.tar'): + tar = 'tar' if sys.platform == 'linux' else 'gtar' + if not invoke(tar + ' --concatenate --file=' + appendTo + '.tar ' + tmppath + '.tar'): os.remove(appendTo + '.tar') os.remove(tmppath + '.tar') return False @@ -163,7 +164,13 @@ if access_token == '': sys.exit(1) print('Version: ' + version_full) -local_folder = expanduser("~") + '/Projects/backup/tdesktop/' + version_major + '/' + version_full +local_base = expanduser("~") + '/Projects/backup/tdesktop' +if not os.path.isdir(local_base): + local_base = '/mnt/c/Telegram/Projects/backup/tdesktop' + if not os.path.isdir(local_base): + print('Backup path not found: ' + local_base) + sys.exit(1) +local_folder = local_base + '/' + version_major + '/' + version_full if stable == 1: if os.path.isdir(local_folder + '.beta'): From 83fc19e14371beaad865371e7c0e79ea7e7a6374 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 16 Jan 2024 16:12:46 +0300 Subject: [PATCH 68/73] Changed behavior in voice record bar to create ttl button on demand. --- .../history_view_voice_record_bar.cpp | 25 +++++++++++++------ .../controls/history_view_voice_record_bar.h | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index 3714bbf8f..04c649c29 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -292,9 +292,10 @@ TTLButton::TTLButton( , _st(st) , _rippleRect(Rect(Size(st::historyRecordLockTopShadow.width())) - (st::historyRecordLockRippleMargin)) { - resize(Size(st::historyRecordLockTopShadow.width())); + QWidget::resize(Size(st::historyRecordLockTopShadow.width())); + Ui::AbstractButton::setDisabled(true); - setClickedCallback([=] { + Ui::AbstractButton::setClickedCallback([=] { Ui::AbstractButton::setDisabled(!Ui::AbstractButton::isDisabled()); const auto isActive = !Ui::AbstractButton::isDisabled(); _activeAnimation.start( @@ -306,7 +307,7 @@ TTLButton::TTLButton( Ui::RpWidget::shownValue() | rpl::filter( rpl::mappers::_1 - ) | rpl::skip(1) | rpl::take(1) | rpl::start_with_next([=] { + ) | rpl::take(1) | rpl::start_with_next([=] { auto text = rpl::conditional( Core::App().settings().ttlVoiceClickTooltipHiddenValue(), tr::lng_record_once_active_tooltip( @@ -400,7 +401,7 @@ TTLButton::TTLButton( void TTLButton::clearState() { Ui::AbstractButton::setDisabled(true); - update(); + QWidget::update(); Ui::RpWidget::hide(); } @@ -1168,7 +1169,6 @@ VoiceRecordBar::VoiceRecordBar( , _show(std::move(descriptor.show)) , _send(std::move(descriptor.send)) , _lock(std::make_unique<RecordLock>(_outerContainer, _st.lock)) -, _ttlButton(std::make_unique<TTLButton>(_outerContainer, _st)) , _level(std::make_unique<VoiceRecordButton>(_outerContainer, _st)) , _cancel(std::make_unique<CancelButton>(this, _st, descriptor.recorderHeight)) , _startTimer([=] { startRecording(); }) @@ -1247,6 +1247,9 @@ void VoiceRecordBar::updateLockGeometry() { void VoiceRecordBar::updateTTLGeometry( TTLAnimationType type, float64 progress) { + if (!_ttlButton) { + return; + } const auto parent = parentWidget(); const auto me = Ui::MapFrom(_outerContainer, parent, geometry()); const auto anyTop = me.y() - st::historyRecordLockPosition.y(); @@ -1406,6 +1409,11 @@ void VoiceRecordBar::init() { _lock->locks( ) | rpl::start_with_next([=] { if (_hasTTLFilter && _hasTTLFilter()) { + if (!_ttlButton) { + _ttlButton = std::make_unique<TTLButton>( + _outerContainer, + _st); + } _ttlButton->show(); } updateTTLGeometry(TTLAnimationType::RightTopStatic, 0); @@ -1869,7 +1877,7 @@ bool VoiceRecordBar::isRecordingByAnotherBar() const { } bool VoiceRecordBar::isTTLButtonShown() const { - return !_ttlButton->isHidden(); + return _ttlButton && !_ttlButton->isHidden(); } bool VoiceRecordBar::hasDuration() const { @@ -1904,10 +1912,13 @@ void VoiceRecordBar::computeAndSetLockProgress(QPoint globalPos) { } bool VoiceRecordBar::peekTTLState() const { - return !_ttlButton->isDisabled(); + return _ttlButton && !_ttlButton->isDisabled(); } bool VoiceRecordBar::takeTTLState() const { + if (!_ttlButton) { + return false; + } const auto hasTtl = !_ttlButton->isDisabled(); _ttlButton->clearState(); return hasTtl; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h index 964614597..f1a58465e 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.h @@ -157,9 +157,9 @@ private: const std::shared_ptr<ChatHelpers::Show> _show; const std::shared_ptr<Ui::SendButton> _send; const std::unique_ptr<RecordLock> _lock; - const std::unique_ptr<Ui::AbstractButton> _ttlButton; const std::unique_ptr<VoiceRecordButton> _level; const std::unique_ptr<CancelButton> _cancel; + std::unique_ptr<Ui::AbstractButton> _ttlButton; std::unique_ptr<ListenWrap> _listen; base::Timer _startTimer; From c4526943483abbee6e43e269c401184decf6e8f4 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 16:54:25 +0400 Subject: [PATCH 69/73] Pause infinite radial timer if anim::Disabled. --- Telegram/lib_ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 564e354c1..cb1a041ca 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 564e354c1d4fabe906cb790babe6879e33faca54 +Subproject commit cb1a041ca363e815cbb9f63804c02b2d02d9818d From d3fdfe4b29e689de0e9269a385d61f1979c2f800 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 21:09:45 +0400 Subject: [PATCH 70/73] Fix crash in themes editor. Fixes #27366. --- .../SourceFiles/window/themes/window_theme_editor_block.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/window/themes/window_theme_editor_block.cpp b/Telegram/SourceFiles/window/themes/window_theme_editor_block.cpp index bd1e5c311..9c0c85cc3 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_editor_block.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_editor_block.cpp @@ -331,9 +331,8 @@ void EditorBlock::activateRow(const Row &row) { const auto state = editor->lifetime().make_state<State>(); const auto save = crl::guard(this, [=] { - saveEditing(editor->color()); state->cancelLifetime.destroy(); - box->closeBox(); + saveEditing(editor->color()); }); box->boxClosing( ) | rpl::start_with_next(crl::guard(this, [=] { From 605b255e327946e0be94bad58acda80d2763cd6c Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 21:12:06 +0400 Subject: [PATCH 71/73] Fix media viewer non-full-screen-ness. --- Telegram/lib_ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/lib_ui b/Telegram/lib_ui index cb1a041ca..30b22ace0 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit cb1a041ca363e815cbb9f63804c02b2d02d9818d +Subproject commit 30b22ace0b67f72e2ab913fccf56842b863effad From 5033b9ef0dde7d763ab955babcf9e51c913e3029 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 21:43:19 +0400 Subject: [PATCH 72/73] Fix crash in ttl video, track editions. --- .../chat_helpers/ttl_media_layer_widget.cpp | 97 +++++++++++++------ 1 file changed, 70 insertions(+), 27 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp index fae8f0c2d..f2445a166 100644 --- a/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/ttl_media_layer_widget.cpp @@ -100,6 +100,9 @@ public: private: void paintEvent(QPaintEvent *e) override; + void createView(); + [[nodiscard]] bool goodItem() const; + void clear(); const not_null<HistoryItem*> _item; const std::unique_ptr<Ui::ChatStyle> _style; @@ -162,6 +165,30 @@ PreviewWrap::PreviewWrap( update(_elementGeometry); } }, lifetime()); + session->data().itemViewRefreshRequest( + ) | rpl::start_with_next([=](not_null<HistoryItem*> item) { + if (item == _item) { + if (goodItem()) { + createView(); + update(); + } else { + clear(); + _closeRequests.fire({}); + } + } + }, lifetime()); + session->data().itemDataChanges( + ) | rpl::start_with_next([=](not_null<HistoryItem*> item) { + if (item == _item) { + _element->itemDataChanged(); + } + }, lifetime()); + session->data().itemRemoved( + ) | rpl::start_with_next([=](not_null<const HistoryItem*> item) { + if (item == _item) { + _closeRequests.fire({}); + } + }, lifetime()); { const auto close = Ui::CreateChild<Ui::RoundButton>( @@ -187,32 +214,7 @@ PreviewWrap::PreviewWrap( } QWidget::setAttribute(Qt::WA_OpaquePaintEvent, false); - _element = _item->createView(_delegate.get()); - - { - _element->initDimensions(); - rpl::combine( - sizeValue(), - _globalViewport.value() - ) | rpl::start_with_next([=](QSize outer, QRect globalViewport) { - _viewport = globalViewport.isEmpty() - ? rect() - : mapFromGlobal(globalViewport); - if (_viewport.width() < st::msgMinWidth) { - return; - } - _element->resizeGetHeight(_viewport.width()); - _elementGeometry = QRect( - (_viewport.width() - _element->width()) / 2, - (_viewport.height() - _element->height()) / 2, - _element->width(), - _element->height() - ).translated(_viewport.topLeft()); - _elementInner = _element->innerGeometry().translated( - _elementGeometry.topLeft()); - update(); - }, _elementLifetime); - } + createView(); { auto text = item->out() @@ -260,11 +262,52 @@ rpl::producer<> PreviewWrap::closeRequests() const { return _closeRequests.events(); } -PreviewWrap::~PreviewWrap() { +bool PreviewWrap::goodItem() const { + const auto media = _item->media(); + if (!media || !media->ttlSeconds()) { + return false; + } + const auto document = media->document(); + return document + && (document->isVoiceMessage() || document->isVideoMessage()); +} + +void PreviewWrap::createView() { + clear(); + _element = _item->createView(_delegate.get()); + _element->initDimensions(); + rpl::combine( + sizeValue(), + _globalViewport.value() + ) | rpl::start_with_next([=](QSize outer, QRect globalViewport) { + _viewport = globalViewport.isEmpty() + ? rect() + : mapFromGlobal(globalViewport); + if (_viewport.width() < st::msgMinWidth) { + return; + } + _element->resizeGetHeight(_viewport.width()); + _elementGeometry = QRect( + (_viewport.width() - _element->width()) / 2, + (_viewport.height() - _element->height()) / 2, + _element->width(), + _element->height() + ).translated(_viewport.topLeft()); + _elementInner = _element->innerGeometry().translated( + _elementGeometry.topLeft()); + update(); + }, _elementLifetime); +} + +void PreviewWrap::clear() { _elementLifetime.destroy(); _element = nullptr; } +PreviewWrap::~PreviewWrap() { + clear(); +} + void PreviewWrap::paintEvent(QPaintEvent *e) { if (!_element || _elementGeometry.isEmpty()) { return; From c364383cf0cfd6949baa113069aa91b92f1a37fd Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 16 Jan 2024 21:44:56 +0400 Subject: [PATCH 73/73] Version 4.14.6. - Fix one-time audio tooltip showing in wrong places. - Fix media viewer showing above taskbar on Windows. - Fix crash in one-time video message playback. --- 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 | 6 ++++++ 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 607a27620..732d62eb2 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ <Identity Name="TelegramMessengerLLP.TelegramDesktop" ProcessorArchitecture="ARCHITECTURE" Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A" - Version="4.14.5.0" /> + Version="4.14.6.0" /> <Properties> <DisplayName>Telegram Desktop</DisplayName> <PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName> diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index ffa88efad..8d807a2a5 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 4,14,5,0 - PRODUCTVERSION 4,14,5,0 + FILEVERSION 4,14,6,0 + PRODUCTVERSION 4,14,6,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "4.14.5.0" + VALUE "FileVersion", "4.14.6.0" VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.14.5.0" + VALUE "ProductVersion", "4.14.6.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 3c128e7a5..b4d675b3f 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 4,14,5,0 - PRODUCTVERSION 4,14,5,0 + FILEVERSION 4,14,6,0 + PRODUCTVERSION 4,14,6,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", "4.14.5.0" + VALUE "FileVersion", "4.14.6.0" VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.14.5.0" + VALUE "ProductVersion", "4.14.6.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 44cb36e25..dfebfcca0 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 = 4014005; -constexpr auto AppVersionStr = "4.14.5"; +constexpr auto AppVersion = 4014006; +constexpr auto AppVersionStr = "4.14.6"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 35cc3ece4..1e9cf236b 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 4014005 +AppVersion 4014006 AppVersionStrMajor 4.14 -AppVersionStrSmall 4.14.5 -AppVersionStr 4.14.5 +AppVersionStrSmall 4.14.6 +AppVersionStr 4.14.6 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 4.14.5 +AppVersionOriginal 4.14.6 diff --git a/changelog.txt b/changelog.txt index 6c316d6e1..996980a6c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,9 @@ +4.14.6 (15.01.24) + +- Fix one-time audio tooltip showing in wrong places. +- Fix media viewer showing above taskbar on Windows. +- Fix crash in one-time video message playback. + 4.14.5 (15.01.24) - Allow sending one-time voice messages.