From f306b11676c5a5307951b469bfb4fa15e3bea542 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 30 Oct 2023 10:46:10 +0400 Subject: [PATCH 01/44] Add id-s only when displayed in profile. --- .../info/profile/info_profile_actions.cpp | 34 +++++++++++++++++-- .../info/profile/info_profile_actions.h | 2 ++ .../info/profile/info_profile_values.cpp | 19 ----------- .../info/profile/info_profile_values.h | 2 -- .../settings/settings_experimental.cpp | 2 +- 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index ad6b8519f..404b82e71 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "info/profile/info_profile_actions.h" +#include "base/options.h" #include "data/data_peer_values.h" #include "data/data_session.h" #include "data/data_folder.h" @@ -71,6 +72,12 @@ namespace Info { namespace Profile { namespace { +base::options::toggle ShowPeerIdBelowAbout({ + .id = kOptionShowPeerIdBelowAbout, + .name = "Show Peer IDs in Profile", + .description = "Show peer IDs from API below their Bio / Description.", +}); + [[nodiscard]] rpl::producer UsernamesSubtext( not_null peer, rpl::producer fallback) { @@ -131,6 +138,27 @@ namespace { return result; } +[[nodiscard]] rpl::producer AboutWithIdValue( + not_null peer) { + + return AboutValue( + peer + ) | rpl::map([=](TextWithEntities &&value) { + if (!ShowPeerIdBelowAbout.value()) { + return std::move(value); + } + using namespace Ui::Text; + if (!value.empty()) { + value.append("\n"); + } + value.append(Italic(u"id: "_q)); + const auto raw = peer->id.value & PeerId::kChatTypeMask; + const auto id = QString::number(raw); + value.append(Link(Italic(id), "internal:copy:" + id)); + return std::move(value); + }); +} + template auto AddActionButton( not_null parent, @@ -406,8 +434,8 @@ object_ptr DetailsFiller::setupInfo() { ? tr::lng_info_about_label() : tr::lng_info_bio_label(); addTranslateToMenu( - addInfoLine(std::move(label), AboutValue(user)).text, - AboutValue(user)); + addInfoLine(std::move(label), AboutWithIdValue(user)).text, + AboutWithIdValue(user)); const auto usernameLine = addInfoOneLine( UsernamesSubtext(_peer, tr::lng_info_username_label()), @@ -1028,6 +1056,8 @@ object_ptr ActionsFiller::fill() { } // namespace +const char kOptionShowPeerIdBelowAbout[] = "show-peer-id-below-about"; + object_ptr SetupDetails( not_null controller, not_null parent, diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.h b/Telegram/SourceFiles/info/profile/info_profile_actions.h index 3dfae7358..fcbc351f5 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.h +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.h @@ -23,6 +23,8 @@ class Controller; namespace Info::Profile { +extern const char kOptionShowPeerIdBelowAbout[]; + object_ptr SetupDetails( not_null controller, not_null parent, diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.cpp b/Telegram/SourceFiles/info/profile/info_profile_values.cpp index 198e73975..878366d15 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "info/profile/info_profile_values.h" -#include "base/options.h" #include "info/profile/info_profile_badge.h" #include "core/application.h" #include "core/click_handler_types.h" @@ -38,12 +37,6 @@ namespace { using UpdateFlag = Data::PeerUpdate::Flag; -base::options::toggle ShowPeerIdBelowAbout({ - .id = kOptionShowPeerIdBelowAbout, - .name = "Show Peer IDs in Profile", - .description = "Show peer IDs from API below their Bio / Description.", -}); - auto PlainAboutValue(not_null peer) { return peer->session().changes().peerFlagsValue( peer, @@ -94,8 +87,6 @@ void StripExternalLinks(TextWithEntities &text) { } // namespace -const char kOptionShowPeerIdBelowAbout[] = "show-peer-id-below-about"; - rpl::producer NameValue(not_null peer) { return peer->session().changes().peerFlagsValue( peer, @@ -218,16 +209,6 @@ TextWithEntities AboutWithEntities( if (stripExternal) { StripExternalLinks(result); } - if (ShowPeerIdBelowAbout.value()) { - using namespace Ui::Text; - if (!result.empty()) { - result.append("\n"); - } - result.append(Italic(u"id: "_q)); - const auto raw = peer->id.value & PeerId::kChatTypeMask; - const auto id = QString::number(raw); - result.append(Link(Italic(id), "internal:copy:" + id)); - } return result; } diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.h b/Telegram/SourceFiles/info/profile/info_profile_values.h index 67c9238fb..b3a110fe4 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.h +++ b/Telegram/SourceFiles/info/profile/info_profile_values.h @@ -35,8 +35,6 @@ enum class SharedMediaType : signed char; namespace Info::Profile { -extern const char kOptionShowPeerIdBelowAbout[]; - inline auto ToSingleLine() { return rpl::map([](const QString &text) { return TextUtilities::SingleLine(text); diff --git a/Telegram/SourceFiles/settings/settings_experimental.cpp b/Telegram/SourceFiles/settings/settings_experimental.cpp index 6104cabb1..c6a9b5cde 100644 --- a/Telegram/SourceFiles/settings/settings_experimental.cpp +++ b/Telegram/SourceFiles/settings/settings_experimental.cpp @@ -19,7 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/launcher.h" #include "chat_helpers/tabbed_panel.h" #include "dialogs/dialogs_widget.h" -#include "info/profile/info_profile_values.h" +#include "info/profile/info_profile_actions.h" #include "lang/lang_keys.h" #include "mainwindow.h" #include "media/player/media_player_instance.h" From a57eecd420ea08e016d147df9c4c2366a5915b21 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 30 Oct 2023 11:16:17 +0400 Subject: [PATCH 02/44] Add option to use old tray icon. New monochrome icon is default for the new installations. Fixes #26983, fixes #26988, fixes #26989, fixes #26991, fixes #27005. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/core/core_settings.cpp | 10 ++++ Telegram/SourceFiles/core/core_settings.h | 10 ++++ .../SourceFiles/platform/linux/tray_linux.h | 4 ++ Telegram/SourceFiles/platform/mac/tray_mac.h | 4 ++ Telegram/SourceFiles/platform/platform_tray.h | 2 + .../SourceFiles/platform/win/tray_win.cpp | 16 ++++-- .../settings/settings_advanced.cpp | 50 +++++++++++++------ Telegram/SourceFiles/tray.cpp | 5 ++ 9 files changed, 83 insertions(+), 19 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 4244b1adf..ddfdafbde 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -546,6 +546,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_workmode_tray" = "Show tray icon"; "lng_settings_workmode_window" = "Show taskbar icon"; "lng_settings_close_to_taskbar" = "Close to taskbar"; +"lng_settings_monochrome_icon" = "Use monochrome icon"; "lng_settings_window_system" = "Window title"; "lng_settings_title_chat_name" = "Show chat name"; "lng_settings_title_account_name" = "Show active account"; diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp index fa5bcfd34..c29531c31 100644 --- a/Telegram/SourceFiles/core/core_settings.cpp +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -344,6 +344,8 @@ QByteArray Settings::serialize() const { for (const auto &id : _recentEmojiSkip) { stream << id; } + stream + << qint32(_trayIconMonochrome.current() ? 1 : 0); } return result; } @@ -451,6 +453,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { quint64 macRoundIconDigest = _macRoundIconDigest.value_or(0); qint32 storiesClickTooltipHidden = _storiesClickTooltipHidden.current() ? 1 : 0; base::flat_set recentEmojiSkip; + qint32 trayIconMonochrome = (_trayIconMonochrome.current() ? 1 : 0); stream >> themesAccentColors; if (!stream.atEnd()) { @@ -701,6 +704,12 @@ void Settings::addFromSerialized(const QByteArray &serialized) { } } } + if (!stream.atEnd()) { + stream >> trayIconMonochrome; + } else { + // Let existing clients use the old value. + trayIconMonochrome = 0; + } if (stream.status() != QDataStream::Ok) { LOG(("App Error: " "Bad data for Core::Settings::constructFromSerialized()")); @@ -894,6 +903,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) { _macRoundIconDigest = macRoundIconDigest ? macRoundIconDigest : std::optional(); _storiesClickTooltipHidden = (storiesClickTooltipHidden == 1); _recentEmojiSkip = std::move(recentEmojiSkip); + _trayIconMonochrome = (trayIconMonochrome == 1); } QString Settings::getSoundPath(const QString &key) const { diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index f25345da6..31b0880b1 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -702,6 +702,15 @@ public: [[nodiscard]] rpl::producer closeToTaskbarChanges() const { return _closeToTaskbar.changes(); } + void setTrayIconMonochrome(bool value) { + _trayIconMonochrome = value; + } + [[nodiscard]] bool trayIconMonochrome() const { + return _trayIconMonochrome.current(); + } + [[nodiscard]] rpl::producer trayIconMonochromeChanges() const { + return _trayIconMonochrome.changes(); + } void setCustomDeviceModel(const QString &model) { _customDeviceModel = model; @@ -918,6 +927,7 @@ private: rpl::variable _workMode = WorkMode::WindowAndTray; base::flags _hiddenGroupCallTooltips; rpl::variable _closeToTaskbar = false; + rpl::variable _trayIconMonochrome = true; rpl::variable _customDeviceModel; rpl::variable _playerRepeatMode; rpl::variable _playerOrderMode; diff --git a/Telegram/SourceFiles/platform/linux/tray_linux.h b/Telegram/SourceFiles/platform/linux/tray_linux.h index dd0175a2c..769fe4409 100644 --- a/Telegram/SourceFiles/platform/linux/tray_linux.h +++ b/Telegram/SourceFiles/platform/linux/tray_linux.h @@ -67,4 +67,8 @@ private: }; +inline bool HasMonochromeSetting() { + return false; +} + } // namespace Platform diff --git a/Telegram/SourceFiles/platform/mac/tray_mac.h b/Telegram/SourceFiles/platform/mac/tray_mac.h index 50014bea2..6667d3cb1 100644 --- a/Telegram/SourceFiles/platform/mac/tray_mac.h +++ b/Telegram/SourceFiles/platform/mac/tray_mac.h @@ -55,4 +55,8 @@ private: }; +inline bool HasMonochromeSetting() { + return false; +} + } // namespace Platform diff --git a/Telegram/SourceFiles/platform/platform_tray.h b/Telegram/SourceFiles/platform/platform_tray.h index 0838b52e4..20deabebf 100644 --- a/Telegram/SourceFiles/platform/platform_tray.h +++ b/Telegram/SourceFiles/platform/platform_tray.h @@ -11,6 +11,8 @@ namespace Platform { class Tray; +[[nodiscard]] bool HasMonochromeSetting(); + } // namespace Platform // Platform dependent implementations. diff --git a/Telegram/SourceFiles/platform/win/tray_win.cpp b/Telegram/SourceFiles/platform/win/tray_win.cpp index 1d99df169..3e7d16b5c 100644 --- a/Telegram/SourceFiles/platform/win/tray_win.cpp +++ b/Telegram/SourceFiles/platform/win/tray_win.cpp @@ -221,18 +221,19 @@ void Tray::updateIcon() { : !controller->sessionController() ? nullptr : &controller->sessionController()->session(); + const auto monochrome = Core::App().settings().trayIconMonochrome(); const auto supportMode = session && session->supportMode(); const auto iconSizeWidth = GetSystemMetrics(SM_CXSMICON); auto iconSmallPixmap16 = Tray::IconWithCounter( CounterLayerArgs(16, counter, muted), true, - true, + monochrome, supportMode); auto iconSmallPixmap32 = Tray::IconWithCounter( CounterLayerArgs(32, counter, muted), true, - true, + monochrome, supportMode); auto iconSmall = QIcon(); iconSmall.addPixmap(iconSmallPixmap16); @@ -339,8 +340,15 @@ QPixmap Tray::IconWithCounter( bool smallIcon, bool monochrome, bool supportMode) { - return Ui::PixmapFromImage( - ImageIconWithCounter(std::move(args), supportMode, smallIcon, monochrome)); + return Ui::PixmapFromImage(ImageIconWithCounter( + std::move(args), + supportMode, + smallIcon, + monochrome)); +} + +bool HasMonochromeSetting() { + return IsDarkTaskbar().has_value(); } } // namespace Platform diff --git a/Telegram/SourceFiles/settings/settings_advanced.cpp b/Telegram/SourceFiles/settings/settings_advanced.cpp index b019cffde..1c10841d0 100644 --- a/Telegram/SourceFiles/settings/settings_advanced.cpp +++ b/Telegram/SourceFiles/settings/settings_advanced.cpp @@ -453,18 +453,35 @@ void SetupSystemIntegrationContent( st::settingsCheckboxPadding)); }; + const auto settings = &Core::App().settings(); if (Platform::TrayIconSupported()) { - const auto trayEnabled = [] { - const auto workMode = Core::App().settings().workMode(); + const auto trayEnabled = [=] { + const auto workMode = settings->workMode(); return (workMode == WorkMode::TrayOnly) || (workMode == WorkMode::WindowAndTray); }; const auto tray = addCheckbox( tr::lng_settings_workmode_tray(), trayEnabled()); + const auto monochrome = Platform::HasMonochromeSetting() + ? addSlidingCheckbox( + tr::lng_settings_monochrome_icon(), + settings->trayIconMonochrome()) + : nullptr; + if (monochrome) { + monochrome->toggle(tray->checked(), anim::type::instant); - const auto taskbarEnabled = [] { - const auto workMode = Core::App().settings().workMode(); + monochrome->entity()->checkedChanges( + ) | rpl::filter([=](bool value) { + return (value != settings->trayIconMonochrome()); + }) | rpl::start_with_next([=](bool value) { + settings->setTrayIconMonochrome(value); + Core::App().saveSettingsDelayed(); + }, monochrome->lifetime()); + } + + const auto taskbarEnabled = [=] { + const auto workMode = settings->workMode(); return (workMode == WorkMode::WindowOnly) || (workMode == WorkMode::WindowAndTray); }; @@ -482,10 +499,10 @@ void SetupSystemIntegrationContent( : WorkMode::WindowOnly; if ((newMode == WorkMode::WindowAndTray || newMode == WorkMode::TrayOnly) - && Core::App().settings().workMode() != newMode) { + && settings->workMode() != newMode) { cSetSeenTrayTooltip(false); } - Core::App().settings().setWorkMode(newMode); + settings->setWorkMode(newMode); Core::App().saveSettingsDelayed(); }; @@ -498,6 +515,9 @@ void SetupSystemIntegrationContent( } else { updateWorkmode(); } + if (monochrome) { + monochrome->toggle(checked, anim::type::normal); + } }, tray->lifetime()); if (taskbar) { @@ -519,19 +539,19 @@ void SetupSystemIntegrationContent( tr::lng_settings_mac_warn_before_quit( lt_text, rpl::single(Platform::ConfirmQuit::QuitKeysString())), - Core::App().settings().macWarnBeforeQuit()); + settings->macWarnBeforeQuit()); warnBeforeQuit->checkedChanges( ) | rpl::filter([=](bool checked) { - return (checked != Core::App().settings().macWarnBeforeQuit()); + return (checked != settings->macWarnBeforeQuit()); }) | rpl::start_with_next([=](bool checked) { - Core::App().settings().setMacWarnBeforeQuit(checked); + settings->setMacWarnBeforeQuit(checked); Core::App().saveSettingsDelayed(); }, warnBeforeQuit->lifetime()); #ifndef OS_MAC_STORE const auto enabled = [] { const auto digest = base::Platform::CurrentCustomAppIconDigest(); - return digest && (Core::App().settings().macRoundIconDigest() == digest); + return digest && (settings->macRoundIconDigest() == digest); }; const auto roundIcon = addCheckbox( tr::lng_settings_mac_round_icon(), @@ -548,7 +568,7 @@ void SetupSystemIntegrationContent( } Window::OverrideApplicationIcon(checked ? IconMacRound() : QImage()); Core::App().refreshApplicationIcon(); - Core::App().settings().setMacRoundIconDigest(digest); + settings->setMacRoundIconDigest(digest); Core::App().saveSettings(); }, roundIcon->lifetime()); #endif // OS_MAC_STORE @@ -557,10 +577,10 @@ void SetupSystemIntegrationContent( if (!Platform::RunInBackground()) { const auto closeToTaskbar = addSlidingCheckbox( tr::lng_settings_close_to_taskbar(), - Core::App().settings().closeToTaskbar()); + settings->closeToTaskbar()); const auto closeToTaskbarShown = std::make_shared>(false); - Core::App().settings().workModeValue( + settings->workModeValue( ) | rpl::start_with_next([=](WorkMode workMode) { *closeToTaskbarShown = !Core::App().tray().has(); }, closeToTaskbar->lifetime()); @@ -568,9 +588,9 @@ void SetupSystemIntegrationContent( closeToTaskbar->toggleOn(closeToTaskbarShown->value()); closeToTaskbar->entity()->checkedChanges( ) | rpl::filter([=](bool checked) { - return (checked != Core::App().settings().closeToTaskbar()); + return (checked != settings->closeToTaskbar()); }) | rpl::start_with_next([=](bool checked) { - Core::App().settings().setCloseToTaskbar(checked); + settings->setCloseToTaskbar(checked); Local::writeSettings(); }, closeToTaskbar->lifetime()); } diff --git a/Telegram/SourceFiles/tray.cpp b/Telegram/SourceFiles/tray.cpp index 108d5fffd..636b7a252 100644 --- a/Telegram/SourceFiles/tray.cpp +++ b/Telegram/SourceFiles/tray.cpp @@ -39,6 +39,11 @@ void Tray::create() { } }, _tray.lifetime()); + Core::App().settings().trayIconMonochromeChanges( + ) | rpl::start_with_next([=] { + updateIconCounters(); + }, _tray.lifetime()); + Core::App().passcodeLockChanges( ) | rpl::start_with_next([=] { rebuildMenu(); From 8e8f6f905f5034191f184d84712fb8a0c4890e98 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Tue, 31 Oct 2023 01:08:26 +0400 Subject: [PATCH 03/44] Build newer meson in snap --- snap/snapcraft.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index feae5eb22..909e91a14 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -182,6 +182,18 @@ parts: rm -rf patches stage: [-./*] + meson-deps: + source: https://github.com/mesonbuild/meson.git + source-depth: 1 + source-branch: 1.2.3 + plugin: nil + build-packages: + - python3-pip + - ninja-build + override-build: | + pip install . + stage: [-./*] + desktop-qt: source: https://github.com/desktop-app/snapcraft-desktop-helpers.git source-subdir: qt @@ -253,7 +265,6 @@ parts: source-tag: 2.78.0 plugin: meson build-packages: - - meson - mm-common - ninja-build - libxml-parser-perl @@ -270,6 +281,8 @@ parts: - -./usr/include - -./usr/lib/$CRAFT_ARCH_TRIPLET/pkgconfig - -./usr/lib/$CRAFT_ARCH_TRIPLET/*.so + after: + - meson-deps libjxl: source: https://github.com/libjxl/libjxl.git From de4eb1e59bcb3faaaf2b326507379c02de2acc74 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Tue, 31 Oct 2023 06:21:53 +0400 Subject: [PATCH 04/44] Disable glib tests and introspection generation in snap --- snap/snapcraft.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 909e91a14..7572364fb 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -277,6 +277,8 @@ parts: - -Dsigc++-3.0:build-documentation=false - -Dsigc++-3.0:build-examples=false - -Dsigc++-3.0:validation=false + - -Dglib:tests=false + - -Dglib:introspection=disabled prime: - -./usr/include - -./usr/lib/$CRAFT_ARCH_TRIPLET/pkgconfig From 8615a25cd13ce972721078814a992abd4f30c4f9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 30 Oct 2023 18:30:26 +0400 Subject: [PATCH 05/44] Fix empty preview if sent while failing generating. Fixes #27004. --- .../SourceFiles/history/view/media/history_view_web_page.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp index 38b6dc258..844963a5e 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp @@ -155,7 +155,7 @@ bool WebPage::HasButton(not_null webpage) { } QSize WebPage::countOptimalSize() { - if (_data->pendingTill) { + if (_data->pendingTill || _data->failed) { return { 0, 0 }; } @@ -366,7 +366,7 @@ QSize WebPage::countOptimalSize() { } QSize WebPage::countCurrentSize(int newWidth) { - if (_data->pendingTill) { + if (_data->pendingTill || _data->failed) { return { newWidth, minHeight() }; } @@ -891,6 +891,7 @@ void WebPage::playAnimation(bool autoplay) { bool WebPage::isDisplayed() const { const auto item = _parent->data(); return !_data->pendingTill + && !_data->failed && !item->Has(); } From d1c310de00118b8d39e734d2f2c6f732b9712be5 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 30 Oct 2023 21:54:00 +0400 Subject: [PATCH 06/44] Highlight reply quote in original message. --- .../admin_log/history_admin_log_inner.cpp | 5 - .../admin_log/history_admin_log_inner.h | 2 - .../history/history_inner_widget.cpp | 20 ++- .../history/history_inner_widget.h | 5 +- .../history/history_item_components.cpp | 5 +- .../history/history_item_helpers.cpp | 10 +- .../history/history_item_helpers.h | 6 +- .../history_view_highlight_manager.cpp | 151 ++++++++++++------ .../history/history_view_highlight_manager.h | 42 +++-- .../SourceFiles/history/history_widget.cpp | 63 +++++--- Telegram/SourceFiles/history/history_widget.h | 22 ++- .../history/view/history_view_element.cpp | 14 +- .../history/view/history_view_element.h | 4 - .../history/view/history_view_list_widget.cpp | 35 ++-- .../history/view/history_view_list_widget.h | 14 +- .../history/view/history_view_message.cpp | 36 ++++- .../view/history_view_pinned_section.cpp | 4 +- .../view/history_view_replies_section.cpp | 14 +- .../view/history_view_replies_section.h | 7 +- .../view/history_view_scheduled_section.cpp | 2 +- .../view/media/history_view_document.cpp | 2 + .../media/history_view_extended_preview.cpp | 2 + .../history/view/media/history_view_gif.cpp | 2 + .../view/media/history_view_media_grouped.cpp | 9 +- .../history/view/media/history_view_photo.cpp | 2 + Telegram/SourceFiles/mainwidget.cpp | 4 +- Telegram/SourceFiles/ui/chat/chat_style.h | 23 +++ .../window/window_session_controller.h | 1 + Telegram/lib_ui | 2 +- 29 files changed, 342 insertions(+), 166 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 deb786a28..89a2e6b49 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -579,11 +579,6 @@ bool InnerWidget::elementUnderCursor( return (Element::Hovered() == view); } -float64 InnerWidget::elementHighlightOpacity( - not_null item) const { - return 0.; -} - bool InnerWidget::elementInSelectionMode() { return false; } diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h index 36c321810..da7653b1b 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h @@ -93,8 +93,6 @@ public: HistoryView::Context elementContext() override; bool elementUnderCursor( not_null view) override; - [[nodiscard]] float64 elementHighlightOpacity( - not_null item) const override; bool elementInSelectionMode() override; bool elementIntersectsRange( not_null view, diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index c4284cd88..2adb08577 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -202,10 +202,6 @@ public: not_null view) override { return (Element::Moused() == view); } - [[nodiscard]] float64 elementHighlightOpacity( - not_null item) const override { - return _widget ? _widget->elementHighlightOpacity(item) : 0.; - } bool elementInSelectionMode() override { return _widget ? _widget->inSelectionMode() : false; } @@ -1060,6 +1056,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { auto clip = e->rect(); auto context = preparePaintContext(clip); + context.highlightPathCache = &_highlightPathCache; _pathGradient->startFrame( 0, width(), @@ -1143,7 +1140,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { } else if (item->isUnreadMention() && !item->isUnreadMedia()) { readContents.insert(item); - _widget->enqueueMessageHighlight(view); + _widget->enqueueMessageHighlight(view, {}); } } session().data().reactions().poll(item, context.now); @@ -1185,6 +1182,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { view, selfromy - mtop, seltoy - mtop); + context.highlight = _widget->itemHighlight(view->data()); view->draw(p, context); processPainted(view, top, height); @@ -1219,9 +1217,10 @@ void HistoryInner::paintEvent(QPaintEvent *e) { const auto &sendingAnimation = _controller->sendingAnimation(); while (top < drawToY) { const auto height = view->height(); + const auto item = view->data(); if ((context.clip.y() < height) && (hdrawtop < top + height) - && !sendingAnimation.hasAnimatedMessage(view->data())) { + && !sendingAnimation.hasAnimatedMessage(item)) { context.reactionInfo = _reactionsManager->currentReactionPaintInfo(); context.outbg = view->hasOutLayout(); @@ -1229,6 +1228,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { view, selfromy - htop, seltoy - htop); + context.highlight = _widget->itemHighlight(item); view->draw(p, context); processPainted(view, top, height); } @@ -2410,6 +2410,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { _menu->addAction(text, [=] { if (canSendReply) { _widget->replyToMessage({ itemId, quote }); + if (!quote.empty()) { + _widget->clearSelected(); + } } else { HistoryView::Controls::ShowReplyToChatBox( controller->uiShow(), @@ -3474,11 +3477,6 @@ void HistoryInner::elementStartStickerLoop( _animatedStickersPlayed.emplace(view->data()); } -float64 HistoryInner::elementHighlightOpacity( - not_null item) const { - return _widget->highlightOpacity(item); -} - void HistoryInner::elementShowPollResults( not_null poll, FullMsgId context) { diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 981b9e424..c6049a844 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -15,6 +15,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/scroll_area.h" #include "history/view/history_view_top_bar_widget.h" +#include + struct ClickContext; struct ClickHandlerContext; @@ -136,8 +138,6 @@ public: int from, int till) const; void elementStartStickerLoop(not_null view); - [[nodiscard]] float64 elementHighlightOpacity( - not_null item) const; void elementShowPollResults( not_null poll, FullMsgId context); @@ -462,6 +462,7 @@ private: std::optional _chooseForReportReason; const std::unique_ptr _pathGradient; + QPainterPath _highlightPathCache; bool _isChatWide = false; base::flat_set> _animatedStickersPlayed; diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index b75292aa0..3562efd91 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -630,7 +630,10 @@ void HistoryMessageReply::setLinkFrom( } }; _link = resolvedMessage - ? JumpToMessageClickHandler(resolvedMessage.get(), holder->fullId()) + ? JumpToMessageClickHandler( + resolvedMessage.get(), + holder->fullId(), + _fields.quote) : resolvedStory ? JumpToStoryClickHandler(resolvedStory.get()) : (external && !_fields.messageId) diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 43f17d19e..15b4555e9 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -259,17 +259,20 @@ bool IsItemScheduledUntilOnline(not_null item) { ClickHandlerPtr JumpToMessageClickHandler( not_null item, - FullMsgId returnToId) { + FullMsgId returnToId, + TextWithEntities highlightPart) { return JumpToMessageClickHandler( item->history()->peer, item->id, - returnToId); + returnToId, + std::move(highlightPart)); } ClickHandlerPtr JumpToMessageClickHandler( not_null peer, MsgId msgId, - FullMsgId returnToId) { + FullMsgId returnToId, + TextWithEntities highlightPart) { return std::make_shared([=] { const auto separate = Core::App().separateWindowForPeer(peer); const auto controller = separate @@ -279,6 +282,7 @@ ClickHandlerPtr JumpToMessageClickHandler( auto params = Window::SectionShow{ Window::SectionShow::Way::Forward }; + params.highlightPart = highlightPart; params.origin = Window::SectionShow::OriginMessage{ returnToId }; diff --git a/Telegram/SourceFiles/history/history_item_helpers.h b/Telegram/SourceFiles/history/history_item_helpers.h index 8dd151274..39e8a4e4b 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.h +++ b/Telegram/SourceFiles/history/history_item_helpers.h @@ -120,10 +120,12 @@ struct SendingErrorRequest { [[nodiscard]] ClickHandlerPtr JumpToMessageClickHandler( not_null peer, MsgId msgId, - FullMsgId returnToId = FullMsgId()); + FullMsgId returnToId = FullMsgId(), + TextWithEntities highlightPart = {}); [[nodiscard]] ClickHandlerPtr JumpToMessageClickHandler( not_null item, - FullMsgId returnToId = FullMsgId()); + FullMsgId returnToId = FullMsgId(), + TextWithEntities highlightPart = {}); [[nodiscard]] ClickHandlerPtr JumpToStoryClickHandler( not_null story); ClickHandlerPtr JumpToStoryClickHandler( diff --git a/Telegram/SourceFiles/history/history_view_highlight_manager.cpp b/Telegram/SourceFiles/history/history_view_highlight_manager.cpp index 939e56980..94244ef00 100644 --- a/Telegram/SourceFiles/history/history_view_highlight_manager.cpp +++ b/Telegram/SourceFiles/history/history_view_highlight_manager.cpp @@ -10,12 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "history/history_item.h" #include "history/view/history_view_element.h" +#include "ui/chat/chat_style.h" namespace HistoryView { -constexpr auto kAnimationFirstPart = st::activeFadeInDuration - / float64(st::activeFadeInDuration + st::activeFadeOutDuration); - ElementHighlighter::ElementHighlighter( not_null data, ViewForItem viewForItem, @@ -26,14 +24,15 @@ ElementHighlighter::ElementHighlighter( , _animation(*this) { } -void ElementHighlighter::enqueue(not_null view) { +void ElementHighlighter::enqueue( + not_null view, + TextSelection part) { const auto item = view->data(); - const auto fullId = item->fullId(); + const auto data = Highlight{ item->fullId(), part }; if (_queue.empty() && !_animation.animating()) { - highlight(fullId); - } else if (_highlightedMessageId != fullId - && !base::contains(_queue, fullId)) { - _queue.push_back(fullId); + highlight(data.itemId, data.part); + } else if (_highlighted != data && !base::contains(_queue, data)) { + _queue.push_back(data); checkNextHighlight(); } } @@ -42,47 +41,46 @@ void ElementHighlighter::checkNextHighlight() { if (_animation.animating()) { return; } - const auto nextHighlight = [&] { + const auto next = [&] { while (!_queue.empty()) { - const auto fullId = _queue.front(); + const auto highlight = _queue.front(); _queue.pop_front(); - if (const auto item = _data->message(fullId)) { + if (const auto item = _data->message(highlight.itemId)) { if (_viewForItem(item)) { - return fullId; + return highlight; } } } - return FullMsgId(); + return Highlight(); }(); - if (!nextHighlight) { + if (!next) { return; } - highlight(nextHighlight); + highlight(next.itemId, next.part); } -float64 ElementHighlighter::progress( +Ui::ChatPaintHighlight ElementHighlighter::state( not_null item) const { - if (item->fullId() == _highlightedMessageId) { - const auto progress = _animation.progress(); - return std::min(progress / kAnimationFirstPart, 1.) - - ((progress - kAnimationFirstPart) / (1. - kAnimationFirstPart)); + if (item->fullId() == _highlighted.itemId) { + auto result = _animation.state(); + result.range = _highlighted.part; + return result; } - return 0.; + return {}; } -void ElementHighlighter::highlight(FullMsgId itemId) { +void ElementHighlighter::highlight(FullMsgId itemId, TextSelection part) { if (const auto item = _data->message(itemId)) { if (const auto view = _viewForItem(item)) { - if (_highlightedMessageId - && _highlightedMessageId != itemId) { - if (const auto was = _data->message(_highlightedMessageId)) { + if (_highlighted && _highlighted.itemId != itemId) { + if (const auto was = _data->message(_highlighted.itemId)) { if (const auto view = _viewForItem(was)) { repaintHighlightedItem(view); } } } - _highlightedMessageId = itemId; - _animation.start(); + _highlighted = { itemId, part }; + _animation.start(!part.empty()); repaintHighlightedItem(view); } @@ -105,7 +103,7 @@ void ElementHighlighter::repaintHighlightedItem( } void ElementHighlighter::updateMessage() { - if (const auto item = _data->message(_highlightedMessageId)) { + if (const auto item = _data->message(_highlighted.itemId)) { if (const auto view = _viewForItem(item)) { repaintHighlightedItem(view); } @@ -114,7 +112,7 @@ void ElementHighlighter::updateMessage() { void ElementHighlighter::clear() { _animation.cancel(); - _highlightedMessageId = FullMsgId(); + _highlighted = {}; _lastHighlightedMessageId = FullMsgId(); _queue.clear(); } @@ -125,60 +123,117 @@ ElementHighlighter::AnimationManager::AnimationManager( } bool ElementHighlighter::AnimationManager::animating() const { - if (anim::Disabled()) { - return (_timer && _timer->isActive()); - } else { + if (_timer && _timer->isActive()) { + return true; + } else if (!anim::Disabled()) { return _simple.animating(); } + return false; } -float64 ElementHighlighter::AnimationManager::progress() const { +Ui::ChatPaintHighlight ElementHighlighter::AnimationManager::state() const { if (anim::Disabled()) { - return (_timer && _timer->isActive()) ? kAnimationFirstPart : 0.; - } else { - return _simple.value(0.); + return { + .opacity = !_timer ? 0. : 1., + .collapsion = !_timer ? 0. : _fadingOut ? 1. : 0., + }; } + return { + .opacity = ((!_fadingOut && _collapsing) + ? 1. + : _simple.value(_fadingOut ? 0. : 1.)), + .collapsion = ((!_withTextPart || !_collapsing) + ? 0. + : _fadingOut + ? 1. + : _simple.value(1.)), + }; } MsgId ElementHighlighter::latestSingleHighlightedMsgId() const { - return _highlightedMessageId - ? _highlightedMessageId.msg + return _highlighted.itemId + ? _highlighted.itemId.msg : _lastHighlightedMessageId.msg; } -void ElementHighlighter::AnimationManager::start() { +void ElementHighlighter::AnimationManager::start(bool withTextPart) { + _withTextPart = withTextPart; const auto finish = [=] { cancel(); _parent._lastHighlightedMessageId = base::take( - _parent._highlightedMessageId); + _parent._highlighted.itemId); _parent.checkNextHighlight(); }; cancel(); if (anim::Disabled()) { _timer.emplace([=] { _parent.updateMessage(); - finish(); + if (_withTextPart && !_fadingOut) { + _fadingOut = true; + _timer->callOnce(st::activeFadeOutDuration); + } else { + finish(); + } }); - _timer->callOnce(st::activeFadeOutDuration); + _timer->callOnce(_withTextPart + ? st::activeFadeInDuration + : st::activeFadeOutDuration); _parent.updateMessage(); } else { - const auto to = 1.; _simple.start( [=](float64 value) { _parent.updateMessage(); - if (value == to) { - finish(); + if (value == 1.) { + if (_withTextPart) { + _timer.emplace([=] { + _parent.updateMessage(); + if (_collapsing) { + _fadingOut = true; + } else { + _collapsing = true; + } + _simple.start([=](float64 value) { + _parent.updateMessage(); + if (_fadingOut && value == 0.) { + finish(); + } else if (!_fadingOut && value == 1.) { + _timer->callOnce( + st::activeFadeOutDuration); + } + }, + _fadingOut ? 1. : 0., + _fadingOut ? 0. : 1., + (_fadingOut + ? st::activeFadeInDuration + : st::fadeWrapDuration)); + }); + _timer->callOnce(st::activeFadeInDuration); + } else { + _fadingOut = true; + _simple.start([=](float64 value) { + _parent.updateMessage(); + if (value == 0.) { + finish(); + } + }, + 1., + 0., + st::activeFadeOutDuration); + } } }, 0., - to, - st::activeFadeInDuration + st::activeFadeOutDuration); + 1., + st::activeFadeInDuration); } } void ElementHighlighter::AnimationManager::cancel() { _simple.stop(); _timer.reset(); + _fadingOut = false; + _collapsed = false; + _collapsing = false; } } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/history_view_highlight_manager.h b/Telegram/SourceFiles/history/history_view_highlight_manager.h index 43372a8b9..f6de65ceb 100644 --- a/Telegram/SourceFiles/history/history_view_highlight_manager.h +++ b/Telegram/SourceFiles/history/history_view_highlight_manager.h @@ -16,6 +16,10 @@ namespace Data { class Session; } // namespace Data +namespace Ui { +struct ChatPaintHighlight; +} // namespace Ui + namespace HistoryView { class Element; @@ -29,40 +33,56 @@ public: ViewForItem viewForItem, RepaintView repaintView); - void enqueue(not_null view); - void highlight(FullMsgId itemId); + void enqueue(not_null view, TextSelection part); + void highlight(FullMsgId itemId, TextSelection part); void clear(); - [[nodiscard]] float64 progress(not_null item) const; + [[nodiscard]] Ui::ChatPaintHighlight state( + not_null item) const; [[nodiscard]] MsgId latestSingleHighlightedMsgId() const; private: - void checkNextHighlight(); - void repaintHighlightedItem(not_null view); - void updateMessage(); - class AnimationManager final { public: AnimationManager(ElementHighlighter &parent); [[nodiscard]] bool animating() const; - [[nodiscard]] float64 progress() const; - void start(); + [[nodiscard]] Ui::ChatPaintHighlight state() const; + void start(bool withTextPart); void cancel(); private: ElementHighlighter &_parent; Ui::Animations::Simple _simple; std::optional _timer; + bool _withTextPart = false; + bool _collapsing = false; + bool _collapsed = false; + bool _fadingOut = false; }; + struct Highlight { + FullMsgId itemId; + TextSelection part; + + explicit operator bool() const { + return itemId.operator bool(); + } + friend inline auto operator<=>(Highlight, Highlight) = default; + friend inline bool operator==(Highlight, Highlight) = default; + }; + + void checkNextHighlight(); + void repaintHighlightedItem(not_null view); + void updateMessage(); + const not_null _data; const ViewForItem _viewForItem; const RepaintView _repaintView; - FullMsgId _highlightedMessageId; + Highlight _highlighted; FullMsgId _lastHighlightedMessageId; - std::deque _queue; + std::deque _queue; AnimationManager _animation; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index a916c4892..681a9b482 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1072,7 +1072,7 @@ void HistoryWidget::initTabbedSelector() { if (!data.recipientOverride) { return true; } else if (data.recipientOverride != _peer) { - showHistory(data.recipientOverride->id, ShowAtTheEndMsgId); + showHistory(data.recipientOverride->id, ShowAtTheEndMsgId, {}); } return (data.recipientOverride == _peer); }) | rpl::start_with_next([=](ChatHelpers::InlineChosen data) { @@ -1267,13 +1267,14 @@ void HistoryWidget::scrollToAnimationCallback( } void HistoryWidget::enqueueMessageHighlight( - not_null view) { - _highlighter.enqueue(view); + not_null view, + TextSelection part) { + _highlighter.enqueue(view, part); } -float64 HistoryWidget::highlightOpacity( +Ui::ChatPaintHighlight HistoryWidget::itemHighlight( not_null item) const { - return _highlighter.progress(item); + return _highlighter.state(item); } int HistoryWidget::itemTopForHighlight( @@ -1971,9 +1972,10 @@ bool HistoryWidget::insideJumpToEndInsteadOfToUnread() const { void HistoryWidget::showHistory( const PeerId &peerId, MsgId showAtMsgId, - bool reload) { + const TextWithEntities &highlightPart) { _pinnedClickedId = FullMsgId(); _minPinnedId = std::nullopt; + _showAtMsgHighlightPart = {}; const auto wasDialogsEntryState = computeDialogsEntryState(); const auto startBot = (showAtMsgId == ShowAndStartBotMsgId); @@ -1985,7 +1987,7 @@ void HistoryWidget::showHistory( controller()->sendingAnimation().clear(); _topToast.hide(anim::type::instant); if (_history) { - if (_peer->id == peerId && !reload) { + if (_peer->id == peerId) { updateForwarding(); if (showAtMsgId == ShowAtUnreadMsgId @@ -2021,10 +2023,10 @@ void HistoryWidget::showHistory( ).arg(_history->inboxReadTillId().bare ).arg(Logs::b(_history->loadedAtBottom()) ).arg(showAtMsgId.bare)); - delayedShowAt(showAtMsgId); + delayedShowAt(showAtMsgId, highlightPart); } else if (_showAtMsgId != showAtMsgId) { clearAllLoadRequests(); - setMsgId(showAtMsgId); + setMsgId(showAtMsgId, highlightPart); firstLoadMessages(); doneShow(); } @@ -2044,7 +2046,7 @@ void HistoryWidget::showHistory( _cornerButtons.skipReplyReturn(skipId); } - setMsgId(showAtMsgId); + setMsgId(showAtMsgId, highlightPart); if (_historyInited) { DEBUG_LOG(("JumpToEnd(%1, %2, %3): " "Showing instant at %4." @@ -2147,6 +2149,7 @@ void HistoryWidget::showHistory( clearInlineBot(); _showAtMsgId = showAtMsgId; + _showAtMsgHighlightPart = highlightPart; _historyInited = false; _contactStatus = nullptr; @@ -3301,7 +3304,7 @@ void HistoryWidget::messagesReceived( } _delayedShowAtRequest = 0; - setMsgId(_delayedShowAtMsgId); + setMsgId(_delayedShowAtMsgId, _delayedShowAtMsgHighlightPart); historyLoaded(); } if (session().supportMode()) { @@ -3523,9 +3526,16 @@ void HistoryWidget::loadMessagesDown() { }); } -void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { - if (!_history - || (_delayedShowAtRequest && _delayedShowAtMsgId == showAtMsgId)) { +void HistoryWidget::delayedShowAt( + MsgId showAtMsgId, + const TextWithEntities &highlightPart) { + if (!_history) { + return; + } + if (_delayedShowAtMsgHighlightPart != highlightPart) { + _delayedShowAtMsgHighlightPart = highlightPart; + } + if (_delayedShowAtRequest && _delayedShowAtMsgId == showAtMsgId) { return; } @@ -4102,7 +4112,12 @@ PeerData *HistoryWidget::peer() const { } // Sometimes _showAtMsgId is set directly. -void HistoryWidget::setMsgId(MsgId showAtMsgId) { +void HistoryWidget::setMsgId( + MsgId showAtMsgId, + const TextWithEntities &highlightPart) { + if (_showAtMsgHighlightPart != highlightPart) { + _showAtMsgHighlightPart = highlightPart; + } if (_showAtMsgId != showAtMsgId) { _showAtMsgId = showAtMsgId; if (_history) { @@ -4223,11 +4238,11 @@ void HistoryWidget::cornerButtonsShowAtPosition( ).arg(_history->peer->name() ).arg(_history->inboxReadTillId().bare ).arg(Logs::b(_history->loadedAtBottom()))); - showHistory(_peer->id, ShowAtUnreadMsgId); + showHistory(_peer->id, ShowAtUnreadMsgId, {}); } else if (_peer && position.fullId.peer == _peer->id) { - showHistory(_peer->id, position.fullId.msg); + showHistory(_peer->id, position.fullId.msg, {}); } else if (_migrated && position.fullId.peer == _migrated->peer->id) { - showHistory(_peer->id, -position.fullId.msg); + showHistory(_peer->id, -position.fullId.msg, {}); } } @@ -5678,14 +5693,17 @@ int HistoryWidget::countInitialScrollTop() { const auto item = getItemFromHistoryOrMigrated(_showAtMsgId); const auto itemTop = _list->itemTop(item); if (itemTop < 0) { - setMsgId(0); + setMsgId(ShowAtUnreadMsgId); controller()->showToast(tr::lng_message_not_found(tr::now)); return countInitialScrollTop(); } else { const auto view = item->mainView(); Assert(view != nullptr); - enqueueMessageHighlight(view); + enqueueMessageHighlight( + view, + view->selectionFromQuote( + base::take(_showAtMsgHighlightPart))); const auto result = itemTopForHighlight(view); createUnreadBarIfBelowVisibleArea(result); return result; @@ -6377,7 +6395,8 @@ void HistoryWidget::handlePeerMigration() { if (_peer != channel) { showHistory( channel->id, - (_showAtMsgId > 0) ? (-_showAtMsgId) : _showAtMsgId); + (_showAtMsgId > 0) ? (-_showAtMsgId) : _showAtMsgId, + {}); channel->session().api().chatParticipants().requestCountDelayed( channel); } else { @@ -6473,7 +6492,7 @@ bool HistoryWidget::showSlowmodeError() { if (const auto item = _history->latestSendingMessage()) { if (const auto view = item->mainView()) { animatedScrollToItem(item->id); - enqueueMessageHighlight(view); + enqueueMessageHighlight(view, {}); } return tr::lng_slowmode_no_many(tr::now); } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index a78875e22..450985010 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -75,6 +75,7 @@ class SpoilerAnimation; enum class ReportReason; class ChooseThemeController; class ContinuousScroll; +struct ChatPaintHighlight; } // namespace Ui namespace Window { @@ -146,7 +147,9 @@ public: void loadMessages(); void loadMessagesDown(); void firstLoadMessages(); - void delayedShowAt(MsgId showAtMsgId); + void delayedShowAt( + MsgId showAtMsgId, + const TextWithEntities &highlightPart); bool updateReplaceMediaButton(); void updateFieldPlaceholder(); @@ -160,7 +163,9 @@ public: History *history() const; PeerData *peer() const; - void setMsgId(MsgId showAtMsgId); + void setMsgId( + MsgId showAtMsgId, + const TextWithEntities &highlightPart = {}); MsgId msgId() const; bool hasTopBarShadow() const { @@ -177,8 +182,10 @@ public: bool touchScroll(const QPoint &delta); - void enqueueMessageHighlight(not_null view); - [[nodiscard]] float64 highlightOpacity( + void enqueueMessageHighlight( + not_null view, + TextSelection part); + [[nodiscard]] Ui::ChatPaintHighlight itemHighlight( not_null item) const; MessageIdsList getSelectedItems() const; @@ -218,7 +225,10 @@ public: void fastShowAtEnd(not_null history); bool applyDraft( FieldHistoryAction fieldHistoryAction = FieldHistoryAction::Clear); - void showHistory(const PeerId &peer, MsgId showAtMsgId, bool reload = false); + void showHistory( + const PeerId &peer, + MsgId showAtMsgId, + const TextWithEntities &highlightPart); void setChooseReportMessagesDetails( Ui::ReportReason reason, Fn callback); @@ -684,12 +694,14 @@ private: bool _canSendMessages = false; bool _canSendTexts = false; MsgId _showAtMsgId = ShowAtUnreadMsgId; + TextWithEntities _showAtMsgHighlightPart; int _firstLoadRequest = 0; // Not real mtpRequestId. int _preloadRequest = 0; // Not real mtpRequestId. int _preloadDownRequest = 0; // Not real mtpRequestId. MsgId _delayedShowAtMsgId = -1; + TextWithEntities _delayedShowAtMsgHighlightPart; int _delayedShowAtRequest = 0; // Not real mtpRequestId. History *_supportPreloadHistory = nullptr; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 61900f20f..ac3cf2ad2 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -111,11 +111,6 @@ bool DefaultElementDelegate::elementUnderCursor( return false; } -float64 DefaultElementDelegate::elementHighlightOpacity( - not_null item) const { - return 0.; -} - bool DefaultElementDelegate::elementInSelectionMode() { return false; } @@ -605,18 +600,13 @@ void Element::paintCustomHighlight( int y, int height, not_null item) const { - const auto opacity = delegate()->elementHighlightOpacity(item); + const auto opacity = context.highlight.opacity; if (opacity == 0.) { return; } const auto o = p.opacity(); p.setOpacity(o * opacity); - p.fillRect( - 0, - y, - width(), - height, - context.st->msgSelectOverlay()); + p.fillRect(0, y, width(), height, context.st->msgSelectOverlay()); p.setOpacity(o); } diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index b51487703..fa8e9e4fa 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -69,8 +69,6 @@ class ElementDelegate { public: virtual Context elementContext() = 0; virtual bool elementUnderCursor(not_null view) = 0; - [[nodiscard]] virtual float64 elementHighlightOpacity( - not_null item) const = 0; virtual bool elementInSelectionMode() = 0; virtual bool elementIntersectsRange( not_null view, @@ -120,8 +118,6 @@ public: class DefaultElementDelegate : public ElementDelegate { public: bool elementUnderCursor(not_null view) override; - [[nodiscard]] float64 elementHighlightOpacity( - not_null item) const override; bool elementInSelectionMode() override; bool elementIntersectsRange( not_null view, diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 2938fffdd..821cab151 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -707,8 +707,15 @@ bool ListWidget::isBelowPosition(Data::MessagePosition position) const { return _items.front()->data()->position() > position; } -void ListWidget::highlightMessage(FullMsgId itemId) { - _highlighter.highlight(itemId); +void ListWidget::highlightMessage( + FullMsgId itemId, + const TextWithEntities &highlightPart) { + const auto view = !highlightPart.empty() + ? viewForItem(itemId) + : nullptr; + _highlighter.highlight( + itemId, + view ? view->selectionFromQuote(highlightPart) : TextSelection()); } void ListWidget::showAroundPosition( @@ -741,12 +748,12 @@ bool ListWidget::jumpToBottomInsteadOfUnread() const { void ListWidget::showAtPosition( Data::MessagePosition position, - anim::type animated, + const Window::SectionShow ¶ms, Fn done) { const auto showAtUnread = (position == Data::UnreadMessagePosition); if (showAtUnread && jumpToBottomInsteadOfUnread()) { - showAtPosition(Data::MaxMessagePosition, animated, std::move(done)); + showAtPosition(Data::MaxMessagePosition, params, std::move(done)); return; } @@ -766,24 +773,24 @@ void ListWidget::showAtPosition( _bar = {}; } checkUnreadBarCreation(); - return showAtPositionNow(position, animated, done); + return showAtPositionNow(position, params, done); }); - } else if (!showAtPositionNow(position, animated, done)) { + } else if (!showAtPositionNow(position, params, done)) { showAroundPosition(position, [=] { - return showAtPositionNow(position, animated, done); + return showAtPositionNow(position, params, done); }); } } bool ListWidget::showAtPositionNow( Data::MessagePosition position, - anim::type animated, + const Window::SectionShow ¶ms, Fn done) { if (const auto scrollTop = scrollTopForPosition(position)) { - computeScrollTo(*scrollTop, position, animated); + computeScrollTo(*scrollTop, position, params.animated); if (position != Data::MaxMessagePosition && position != Data::UnreadMessagePosition) { - highlightMessage(position.fullId); + highlightMessage(position.fullId, params.highlightPart); } if (done) { const auto found = !position.fullId.peer @@ -1655,11 +1662,6 @@ bool ListWidget::elementUnderCursor( return (_overElement == view); } -float64 ListWidget::elementHighlightOpacity( - not_null item) const { - return _highlighter.progress(item); -} - bool ListWidget::elementInSelectionMode() { return inSelectionMode(); } @@ -2108,6 +2110,7 @@ void ListWidget::paintEvent(QPaintEvent *e) { = _reactionsManager->currentReactionPaintInfo(); context.outbg = view->hasOutLayout(); context.selection = itemRenderSelection(view); + context.highlight = _highlighter.state(item); view->draw(p, context); } if (_translateTracker) { @@ -2142,7 +2145,7 @@ void ListWidget::paintEvent(QPaintEvent *e) { } else if (item->isUnreadMention() && !item->isUnreadMedia()) { readContents.insert(item); - _highlighter.enqueue(view); + _highlighter.enqueue(view, {}); } } session->data().reactions().poll(item, context.now); diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index 138f39cca..c12ae113c 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -48,6 +48,10 @@ struct ChosenReaction; struct ButtonParameters; } // namespace HistoryView::Reactions +namespace Window { +struct SectionShow; +} // namespace Window + namespace HistoryView { struct TextState; @@ -227,11 +231,13 @@ public: [[nodiscard]] bool animatedScrolling() const; bool isAbovePosition(Data::MessagePosition position) const; bool isBelowPosition(Data::MessagePosition position) const; - void highlightMessage(FullMsgId itemId); + void highlightMessage( + FullMsgId itemId, + const TextWithEntities &highlightPart); void showAtPosition( Data::MessagePosition position, - anim::type animated = anim::type::normal, + const Window::SectionShow ¶ms, Fn done = nullptr); void refreshViewer(); @@ -292,8 +298,6 @@ public: // ElementDelegate interface. Context elementContext() override; bool elementUnderCursor(not_null view) override; - [[nodiscard]] float64 elementHighlightOpacity( - not_null item) const override; bool elementInSelectionMode() override; bool elementIntersectsRange( not_null view, @@ -430,7 +434,7 @@ private: Fn overrideInitialScroll); bool showAtPositionNow( Data::MessagePosition position, - anim::type animated, + const Window::SectionShow ¶ms, Fn done); Ui::ChatPaintContext preparePaintContext(const QRect &clip) const; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index a5eebddfd..c7d532d27 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1018,6 +1018,10 @@ void Message::draw(Painter &p, const PaintContext &context) const { p.translate(-reactionsPosition); } + if (context.highlightPathCache) { + context.highlightInterpolateTo = g; + context.highlightPathCache->clear(); + } if (bubble) { if (displayFromName() && item->displayFrom() @@ -1110,6 +1114,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { - (_bottomInfo.height() - st::msgDateFont->height)); } auto textSelection = context.selection; + auto highlightRange = context.highlight.range; const auto mediaHeight = mediaDisplayed ? media->height() : 0; const auto paintMedia = [&](int top) { if (!mediaDisplayed) { @@ -1130,6 +1135,10 @@ void Message::draw(Painter &p, const PaintContext &context) const { context.reactionInfo->effectOffset -= add; } } + if (context.highlightPathCache + && !context.highlightPathCache->isEmpty()) { + context.highlightPathCache->translate(mediaPosition); + } p.translate(-mediaPosition); }; if (mediaDisplayed && _invertMedia) { @@ -1141,8 +1150,12 @@ void Message::draw(Painter &p, const PaintContext &context) const { + mediaHeight + (mediaOnBottom ? 0 : st::mediaInBubbleSkip)); textSelection = media->skipSelection(textSelection); + highlightRange = media->skipSelection(highlightRange); } - paintText(p, trect, context.withSelection(textSelection)); + auto copy = context; + copy.selection = textSelection; + copy.highlight.range = highlightRange; + paintText(p, trect, copy); if (mediaDisplayed && !_invertMedia) { paintMedia(trect.y() + trect.height() - mediaHeight); if (context.reactionInfo && !displayInfo && !_reactions) { @@ -1224,6 +1237,20 @@ void Message::draw(Painter &p, const PaintContext &context) const { p.restoreTextPalette(); + if (context.highlightPathCache + && !context.highlightPathCache->isEmpty()) { + const auto alpha = int(0.25 + * context.highlight.collapsion + * context.highlight.opacity + * 255); + if (alpha > 0) { + context.highlightPathCache->setFillRule(Qt::WindingFill); + auto color = context.messageStyle()->textPalette.linkFg->c; + color.setAlpha(alpha); + p.fillPath(*context.highlightPathCache, color); + } + } + if (roll) { p.restore(); } @@ -1651,6 +1678,7 @@ void Message::paintText( width()); trect.setY(trect.y() + botTop->height); } + auto highlightRequest = context.computeHighlightCache(); text().draw(p, { .position = trect.topLeft(), .availableWidth = trect.width(), @@ -1663,6 +1691,7 @@ void Message::paintText( .pausedEmoji = context.paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler), .selection = context.selection, + .highlight = highlightRequest ? &*highlightRequest : nullptr, }); } @@ -2732,10 +2761,13 @@ TextWithEntities Message::selectedQuote( TextSelection Message::selectionFromQuote( const TextWithEntities "e) const { + if (quote.empty()) { + return {}; + } const auto item = data(); const auto &translated = item->translatedText(); const auto &original = item->originalText(); - if (&translated != &original || quote.empty()) { + if (&translated != &original) { return {}; } else if (hasVisibleText()) { const auto media = this->media(); diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index 0fbaf0349..0472e4eb1 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -262,7 +262,7 @@ void PinnedWidget::showAtPosition( FullMsgId originId) { _inner->showAtPosition( position, - anim::type::normal, + {}, _cornerButtons.doneJumpFrom(position.fullId, originId)); } @@ -346,7 +346,7 @@ void PinnedWidget::restoreState(not_null memento) { ? FullMsgId(_history->peer->id, highlight) : FullMsgId(_migratedPeer->id, -highlight)), .date = TimeId(0), - }, anim::type::instant); + }, { Window::SectionShow::Way::Forward, anim::type::instant }); } } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 1048b98b9..f67568e1b 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -1859,16 +1859,22 @@ void RepliesWidget::finishSending() { refreshTopBarActiveChat(); } +void RepliesWidget::showAtPosition( + Data::MessagePosition position, + FullMsgId originItemId) { + showAtPosition(position, originItemId, {}); +} + void RepliesWidget::showAtPosition( Data::MessagePosition position, FullMsgId originItemId, - anim::type animated) { + const Window::SectionShow ¶ms) { _lastShownAt = position.fullId; controller()->setActiveChatEntry(activeChat()); const auto ignore = (position.fullId.msg == _rootId); _inner->showAtPosition( position, - animated, + params, _cornerButtons.doneJumpFrom(position.fullId, originItemId, ignore)); } @@ -2030,7 +2036,7 @@ bool RepliesWidget::showMessage( const auto originItemId = (_cornerButtons.replyReturn() != originMessage) ? originMessage->fullId() : FullMsgId(); - showAtPosition(message->position(), originItemId); + showAtPosition(message->position(), originItemId, params); return true; } @@ -2136,7 +2142,7 @@ void RepliesWidget::restoreState(not_null memento) { showAtPosition(Data::MessagePosition{ .fullId = FullMsgId(_history->peer->id, highlight), .date = TimeId(0), - }, {}, anim::type::instant); + }, {}, { Window::SectionShow::Way::Forward, anim::type::instant }); } } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index 14104e913..cea372614 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -208,8 +208,11 @@ private: void showAtEnd(); void showAtPosition( Data::MessagePosition position, - FullMsgId originItemId = {}, - anim::type animated = anim::type::normal); + FullMsgId originItemId = {}); + void showAtPosition( + Data::MessagePosition position, + FullMsgId originItemId, + const Window::SectionShow ¶ms); void finishSending(); void setupComposeControls(); diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 1ee20e414..81fe77299 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -858,7 +858,7 @@ void ScheduledWidget::showAtPosition( FullMsgId originId) { _inner->showAtPosition( position, - anim::type::normal, + {}, _cornerButtons.doneJumpFrom(position.fullId, originId)); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 5e45b8877..7346966da 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -744,6 +744,7 @@ void Document::draw( if (const auto captioned = Get()) { p.setPen(stm->historyTextFg); _parent->prepareCustomEmojiPaint(p, context, captioned->caption); + auto highlightRequest = context.computeHighlightCache(); captioned->caption.draw(p, { .position = { st::msgPadding.left(), captiontop }, .availableWidth = captionw, @@ -756,6 +757,7 @@ void Document::draw( .pausedEmoji = context.paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler), .selection = selection, + .highlight = highlightRequest ? &*highlightRequest : nullptr, }); } } diff --git a/Telegram/SourceFiles/history/view/media/history_view_extended_preview.cpp b/Telegram/SourceFiles/history/view/media/history_view_extended_preview.cpp index 6c259748d..a82fd13fd 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_extended_preview.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_extended_preview.cpp @@ -229,6 +229,7 @@ void ExtendedPreview::draw(Painter &p, const PaintContext &context) const { if (!_caption.isEmpty()) { p.setPen(stm->historyTextFg); _parent->prepareCustomEmojiPaint(p, context, _caption); + auto highlightRequest = context.computeHighlightCache(); _caption.draw(p, { .position = QPoint( st::msgPadding.left(), @@ -243,6 +244,7 @@ void ExtendedPreview::draw(Painter &p, const PaintContext &context) const { .pausedEmoji = context.paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler), .selection = context.selection, + .highlight = highlightRequest ? &*highlightRequest : nullptr, }); } else if (!inWebPage) { auto fullRight = paintx + paintw; diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 70a81264d..d35658d88 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -716,6 +716,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const { _parent->width()); top += botTop->height; } + auto highlightRequest = context.computeHighlightCache(); _caption.draw(p, { .position = QPoint(st::msgPadding.left(), top), .availableWidth = captionw, @@ -728,6 +729,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const { .pausedEmoji = context.paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler), .selection = context.selection, + .highlight = highlightRequest ? &*highlightRequest : nullptr, }); } else if (!inWebPage && !skipDrawingSurrounding) { auto fullRight = paintx + usex + usew; diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp index 79cbcf869..37676611d 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp @@ -325,12 +325,13 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { : IsGroupItemSelection(selection, i) ? FullSelection : TextSelection()); + const auto highlightOpacity = IsGroupItemSelection( + context.highlight.range, + i + ) ? context.highlight.opacity : 0.; if (textSelection) { selection = part.content->skipSelection(selection); } - const auto highlightOpacity = (_mode == Mode::Grid) - ? _parent->delegate()->elementHighlightOpacity(part.item) - : 0.; if (!part.cache.isNull()) { wasCache = true; } @@ -361,6 +362,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { const auto stm = context.messageStyle(); p.setPen(stm->historyTextFg); _parent->prepareCustomEmojiPaint(p, context, _caption); + auto highlightRequest = context.computeHighlightCache(); _caption.draw(p, { .position = QPoint( st::msgPadding.left(), @@ -375,6 +377,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { .pausedEmoji = context.paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler), .selection = context.selection, + .highlight = highlightRequest ? &*highlightRequest : nullptr, }); } else if (_parent->media() == this) { auto fullRight = width(); diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index 81dee1c54..b0afe1b64 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -401,6 +401,7 @@ void Photo::draw(Painter &p, const PaintContext &context) const { _parent->width()); top += botTop->height; } + auto highlightRequest = context.computeHighlightCache(); _caption.draw(p, { .position = QPoint(st::msgPadding.left(), top), .availableWidth = captionw, @@ -413,6 +414,7 @@ void Photo::draw(Painter &p, const PaintContext &context) const { .pausedEmoji = context.paused || On(PowerSaving::kEmojiChat), .pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler), .selection = context.selection, + .highlight = highlightRequest ? &*highlightRequest : nullptr, }); } else if (!inWebPage) { auto fullRight = paintx + paintw; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 4cc65c77a..2540e2c98 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1411,7 +1411,7 @@ void MainWidget::showHistory( && way != Way::Forward) { clearBotStartToken(_history->peer()); } - _history->showHistory(peerId, showAtMsgId); + _history->showHistory(peerId, showAtMsgId, params.highlightPart); if (alreadyThatPeer && params.reapplyLocalDraft) { _history->applyDraft(HistoryWidget::FieldHistoryAction::NewEntry); } @@ -1772,7 +1772,7 @@ void MainWidget::showNewSection( } else { _mainSection = std::move(newMainSection); _history->finishAnimating(); - _history->showHistory(0, 0); + _history->showHistory(0, 0, {}); if (const auto entry = _mainSection->activeChat(); entry.key) { _controller->setActiveChatEntry(entry); diff --git a/Telegram/SourceFiles/ui/chat/chat_style.h b/Telegram/SourceFiles/ui/chat/chat_style.h index 8ba606941..39f5a76e4 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.h +++ b/Telegram/SourceFiles/ui/chat/chat_style.h @@ -142,6 +142,12 @@ struct BackgroundEmojiData { uint8 colorIndexPlusOne); }; +struct ChatPaintHighlight { + float64 opacity = 0.; + float64 collapsion = 0.; + TextSelection range; +}; + struct ChatPaintContext { not_null st; const BubblePattern *bubblesPattern = nullptr; @@ -149,11 +155,15 @@ struct ChatPaintContext { QRect viewport; QRect clip; TextSelection selection; + ChatPaintHighlight highlight; + QPainterPath *highlightPathCache = nullptr; + mutable QRect highlightInterpolateTo; crl::time now = 0; void translate(int x, int y) { viewport.translate(x, y); clip.translate(x, y); + highlightInterpolateTo.translate(x, y); } void translate(QPoint point) { translate(point.x(), point.y()); @@ -181,6 +191,19 @@ struct ChatPaintContext { result.selection = selection; return result; } + [[nodiscard]] auto computeHighlightCache() const + -> std::optional { + if (highlight.range.empty() || highlight.collapsion <= 0.) { + return {}; + } + return Ui::Text::HighlightInfoRequest{ + .range = highlight.range, + .interpolateTo = highlightInterpolateTo, + .interpolateProgress = (1. - highlight.collapsion), + .outPath = highlightPathCache, + }; + }; + // This is supported only in unwrapped media for now. enum class SkipDrawingParts { diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 367be098f..0bca576aa 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -166,6 +166,7 @@ struct SectionShow { return copy; } + TextWithEntities highlightPart; Way way = Way::Forward; anim::type animated = anim::type::normal; anim::activation activation = anim::activation::normal; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index dc8313f6a..6dc93b53a 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit dc8313f6ae6c87572512424818b9e24e7ef2383e +Subproject commit 6dc93b53a1c4d237dea0a458d2b02c4171529f18 From 475b2ac739fb4c495c4e46ef71588768afd1ad55 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 09:01:01 +0400 Subject: [PATCH 07/44] Fix external quote-reply to topic message. --- .../history/view/history_view_list_widget.cpp | 1 + .../history/view/history_view_list_widget.h | 1 + .../history/view/history_view_message.cpp | 4 +++- .../view/history_view_replies_section.cpp | 19 +++++++++++++------ .../view/history_view_replies_section.h | 9 +++++++-- .../window/window_session_controller.cpp | 3 ++- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 821cab151..07f63ce4f 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2090,6 +2090,7 @@ void ListWidget::paintEvent(QPaintEvent *e) { }); auto context = preparePaintContext(clip); + context.highlightPathCache = &_highlightPathCache; if (from == end(_items)) { _delegate->listPaintEmpty(p, context); return; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index c12ae113c..fd56b9313 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -649,6 +649,7 @@ private: base::flat_map _hiddenSenderUserpics; const std::unique_ptr _pathGradient; + QPainterPath _highlightPathCache; base::unique_qptr _emptyInfo = nullptr; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index c7d532d27..cf2d82973 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1123,6 +1123,8 @@ void Message::draw(Painter &p, const PaintContext &context) const { const auto mediaSelection = _invertMedia ? context.selection : skipTextSelection(context.selection); + const auto maybeMediaHighlight = context.highlightPathCache + && context.highlightPathCache->isEmpty(); auto mediaPosition = QPoint(inner.left(), top); p.translate(mediaPosition); media->draw(p, context.translated( @@ -1135,7 +1137,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { context.reactionInfo->effectOffset -= add; } } - if (context.highlightPathCache + if (maybeMediaHighlight && !context.highlightPathCache->isEmpty()) { context.highlightPathCache->translate(mediaPosition); } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index f67568e1b..32983df4d 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -128,10 +128,12 @@ rpl::producer RootViewContent( RepliesMemento::RepliesMemento( not_null history, MsgId rootId, - MsgId highlightId) + MsgId highlightId, + const TextWithEntities &highlightPart) : _history(history) , _rootId(rootId) -, _highlightId(highlightId) { +, _highlightId(highlightId) +, _highlightPart(highlightPart) { if (highlightId) { _list.setAroundPosition({ .fullId = FullMsgId(_history->peer->id, highlightId), @@ -1966,7 +1968,7 @@ bool RepliesWidget::showInternal( if (logMemento->getHistory() == history() && logMemento->getRootId() == _rootId) { restoreState(logMemento); - if (!logMemento->getHighlightId()) { + if (!logMemento->highlightId()) { showAtPosition(Data::UnreadMessagePosition); } if (params.reapplyLocalDraft) { @@ -2033,7 +2035,8 @@ bool RepliesWidget::showMessage( if (!originMessage) { return false; } - const auto originItemId = (_cornerButtons.replyReturn() != originMessage) + const auto currentReplyReturn = _cornerButtons.replyReturn(); + const auto originItemId = (currentReplyReturn != originMessage) ? originMessage->fullId() : FullMsgId(); showAtPosition(message->position(), originItemId, params); @@ -2138,11 +2141,15 @@ void RepliesWidget::restoreState(not_null memento) { } _cornerButtons.setReplyReturns(memento->replyReturns()); _inner->restoreState(memento->list()); - if (const auto highlight = memento->getHighlightId()) { + if (const auto highlight = memento->highlightId()) { + auto params = Window::SectionShow( + Window::SectionShow::Way::Forward, + anim::type::instant); + params.highlightPart = memento->highlightPart(); showAtPosition(Data::MessagePosition{ .fullId = FullMsgId(_history->peer->id, highlight), .date = TimeId(0), - }, {}, { Window::SectionShow::Way::Forward, anim::type::instant }); + }, {}, params); } } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index cea372614..e8d3e6139 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -380,7 +380,8 @@ public: RepliesMemento( not_null history, MsgId rootId, - MsgId highlightId = 0); + MsgId highlightId = 0, + const TextWithEntities &highlightPart = {}); explicit RepliesMemento( not_null commentsItem, MsgId commentId = 0); @@ -424,9 +425,12 @@ public: [[nodiscard]] not_null list() { return &_list; } - [[nodiscard]] MsgId getHighlightId() const { + [[nodiscard]] MsgId highlightId() const { return _highlightId; } + [[nodiscard]] const TextWithEntities &highlightPart() const { + return _highlightPart; + } private: void setupTopicViewer(); @@ -434,6 +438,7 @@ private: const not_null _history; MsgId _rootId = 0; const MsgId _highlightId = 0; + const TextWithEntities _highlightPart; ListMemento _list; std::shared_ptr _replies; QVector _replyReturns; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 71de8d7b1..3fbfd8145 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -850,7 +850,8 @@ void SessionNavigation::showRepliesForMessage( auto memento = std::make_shared( history, rootId, - commentId); + commentId, + params.highlightPart); memento->setFromTopic(topic); showSection(std::move(memento), params); return; From b793c0675973b4ddfefed9ed04de7443d1aee013 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 10:39:54 +0400 Subject: [PATCH 08/44] Fix external replies in topic groups. --- Telegram/SourceFiles/api/api_sending.cpp | 2 -- Telegram/SourceFiles/apiwrap.cpp | 2 -- Telegram/SourceFiles/data/data_histories.cpp | 5 +++- Telegram/SourceFiles/history/history_item.cpp | 20 ++++++++++--- .../history/history_item_components.cpp | 5 ++-- .../history/history_item_components.h | 4 +++ .../history/history_item_helpers.cpp | 29 +++++++++++++++---- .../history/history_item_helpers.h | 3 ++ .../SourceFiles/history/history_widget.cpp | 2 +- .../history_view_compose_controls.cpp | 6 +++- .../controls/history_view_forward_panel.cpp | 7 ----- .../controls/history_view_forward_panel.h | 1 - .../view/history_view_replies_section.cpp | 10 +++---- Telegram/lib_ui | 2 +- 14 files changed, 65 insertions(+), 33 deletions(-) diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp index 09001ae35..a0d6f4d95 100644 --- a/Telegram/SourceFiles/api/api_sending.cpp +++ b/Telegram/SourceFiles/api/api_sending.cpp @@ -270,7 +270,6 @@ bool SendDice(MessageToSend &message) { flags |= MessageFlag::HasReplyInfo; sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to; } - const auto replyHeader = NewMessageReplyHeader(message.action); const auto anonymousPost = peer->amAnonymous(); const auto silentPost = ShouldSendSilent(peer, message.action.options); InnerFillMessagePostFlags(message.action.options, peer, flags); @@ -399,7 +398,6 @@ void SendConfirmedFile( if (file->to.replyTo) { flags |= MessageFlag::HasReplyInfo; } - const auto replyHeader = NewMessageReplyHeader(action); const auto anonymousPost = peer->amAnonymous(); const auto silentPost = ShouldSendSilent(peer, file->to.options); FillMessagePostFlags(action, peer, flags); diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 1efb5a275..990678304 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -3376,7 +3376,6 @@ void ApiWrap::sendSharedContact( if (action.replyTo) { flags |= MessageFlag::HasReplyInfo; } - const auto replyHeader = NewMessageReplyHeader(action); FillMessagePostFlags(action, peer, flags); if (action.options.scheduled) { flags |= MessageFlag::IsOrWasScheduled; @@ -3640,7 +3639,6 @@ void ApiWrap::sendMessage(MessageToSend &&message) { const auto manualWebPage = exactWebPage && !ignoreWebPage && (message.webPage.manual || (isLast && !isFirst)); - const auto replyHeader = NewMessageReplyHeader(action); MTPMessageMedia media = MTP_messageMediaEmpty(); if (ignoreWebPage) { sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage; diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index b1ba12e13..fb5a116cc 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/notifications_manager.h" #include "history/history.h" #include "history/history_item.h" +#include "history/history_item_helpers.h" #include "history/view/history_view_element.h" #include "core/application.h" #include "apiwrap.h" @@ -46,8 +47,10 @@ MTPInputReplyTo ReplyToForMTP( } } } else if (replyTo.messageId || replyTo.topicRootId) { + const auto to = LookupReplyTo(history, replyTo.messageId); const auto external = replyTo.messageId - && (replyTo.messageId.peer != history->peer->id); + && (replyTo.messageId.peer != history->peer->id + || (replyTo.topicRootId != to->topicRootId())); const auto quoteEntities = Api::EntitiesToMTP( &history->session(), replyTo.quote.entities, diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 6cf62353c..7fd3fe5df 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -3337,16 +3337,28 @@ void HistoryItem::createComponentsHelper( ? replyTo.messageId.peer : PeerId(); const auto to = LookupReplyTo(_history, replyTo.messageId); - const auto replyToTop = LookupReplyToTop(_history, to); + const auto replyToTop = replyTo.topicRootId + ? replyTo.topicRootId + : LookupReplyToTop(_history, to); config.reply.topMessageId = replyToTop ? replyToTop : (replyTo.messageId.peer == history()->peer->id) ? replyTo.messageId.msg : MsgId(); + if (!config.reply.externalPeerId + && to + && config.reply.topicPost + && replyTo.topicRootId != to->topicRootId()) { + config.reply.externalPeerId = replyTo.messageId.peer; + } const auto forum = _history->asForum(); - config.reply.topicPost = LookupReplyIsTopicPost(to) - || (to && to->Has()) - || (forum && forum->creating(config.reply.topMessageId)); + config.reply.topicPost = config.reply.externalPeerId + ? (replyTo.topicRootId + && (replyTo.topicRootId != Data::ForumTopic::kGeneralId)) + : (LookupReplyIsTopicPost(to) + || (to && to->Has()) + || (forum && forum->creating(config.reply.topMessageId))); + config.reply.manualQuote = !replyTo.quote.empty(); config.reply.quote = std::move(replyTo.quote); } config.markup = std::move(markup); diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 3562efd91..006bbced4 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -426,6 +426,7 @@ ReplyFields ReplyFieldsFromMTP( &owner->session(), data.vquote_entities().value_or_empty()), }; + result.manualQuote = data.is_quote(); return result; }, [&](const MTPDmessageReplyStoryHeader &data) { return ReplyFields{ @@ -633,7 +634,7 @@ void HistoryMessageReply::setLinkFrom( ? JumpToMessageClickHandler( resolvedMessage.get(), holder->fullId(), - _fields.quote) + _fields.manualQuote ? _fields.quote : TextWithEntities()) : resolvedStory ? JumpToStoryClickHandler(resolvedStory.get()) : (external && !_fields.messageId) @@ -835,7 +836,7 @@ void HistoryMessageReply::paint( y += st::historyReplyTop; const auto rect = QRect(x, y, w, _height); - const auto hasQuote = !_fields.quote.empty(); + const auto hasQuote = _fields.manualQuote && !_fields.quote.empty(); const auto selected = context.selected(); const auto colorPeer = resolvedMessage ? resolvedMessage->displayFrom() diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index c3bf23770..2b5a90c57 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -239,6 +239,7 @@ struct ReplyFields { MsgId topMessageId = 0; StoryId storyId = 0; bool topicPost = false; + bool manualQuote = false; }; [[nodiscard]] ReplyFields ReplyFieldsFromMTP( @@ -321,6 +322,9 @@ struct HistoryMessageReply [[nodiscard]] bool topicPost() const { return _fields.topicPost; } + [[nodiscard]] bool manualQuote() const { + return _fields.manualQuote; + } [[nodiscard]] QString statePhrase() const; void setLinkFrom(not_null holder); diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 15b4555e9..7ed2db5cf 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "history/history_item_helpers.h" +#include "api/api_text_entities.h" #include "calls/calls_instance.h" #include "data/notify/data_notify_settings.h" #include "data/data_chat_participant_status.h" @@ -202,6 +203,14 @@ MsgId LookupReplyToTop(not_null history, HistoryItem *replyTo) { : 0; } +MsgId LookupReplyToTop(not_null history, FullReplyTo replyTo) { + return replyTo.topicRootId + ? replyTo.topicRootId + : LookupReplyToTop( + history, + LookupReplyTo(history, replyTo.messageId)); +} + bool LookupReplyIsTopicPost(HistoryItem *replyTo) { return replyTo && (replyTo->topicRootId() != Data::ForumTopic::kGeneralId); @@ -373,19 +382,27 @@ MTPMessageReplyHeader NewMessageReplyHeader(const Api::SendAction &action) { const auto externalPeerId = (replyTo.messageId.peer == historyPeer) ? PeerId() : replyTo.messageId.peer; - const auto to = LookupReplyTo(action.history, replyTo.messageId); - const auto replyToTop = LookupReplyToTop(action.history, to); + const auto replyToTop = LookupReplyToTop(action.history, replyTo); + auto quoteEntities = Api::EntitiesToMTP( + &action.history->session(), + replyTo.quote.entities, + Api::ConvertOption::SkipLocal); return MTP_messageReplyHeader( MTP_flags(Flag::f_reply_to_msg_id | (replyToTop ? Flag::f_reply_to_top_id : Flag()) - | (externalPeerId ? Flag::f_reply_to_peer_id : Flag())), + | (externalPeerId ? Flag::f_reply_to_peer_id : Flag()) + | (replyTo.quote.empty() ? Flag() : Flag::f_quote) + | (replyTo.quote.empty() ? Flag() : Flag::f_quote_text) + | (quoteEntities.v.empty() + ? Flag() + : Flag::f_quote_entities)), MTP_int(replyTo.messageId.msg), peerToMTP(externalPeerId), MTPMessageFwdHeader(), // reply_from MTPMessageMedia(), // reply_media - MTP_int(replyToTop), // reply_to_top_id - MTPstring(), // quote_text - MTPVector()); // quote_entities + MTP_int(replyToTop), + MTP_string(replyTo.quote.text), + quoteEntities); } return MTPMessageReplyHeader(); } diff --git a/Telegram/SourceFiles/history/history_item_helpers.h b/Telegram/SourceFiles/history/history_item_helpers.h index 39e8a4e4b..cf1045abd 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.h +++ b/Telegram/SourceFiles/history/history_item_helpers.h @@ -89,6 +89,9 @@ void RequestDependentMessageStory( [[nodiscard]] MsgId LookupReplyToTop( not_null history, HistoryItem *replyTo); +[[nodiscard]] MsgId LookupReplyToTop( + not_null history, + FullReplyTo replyTo); [[nodiscard]] bool LookupReplyIsTopicPost(HistoryItem *replyTo); struct SendingErrorRequest { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 681a9b482..289438e5b 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6320,7 +6320,7 @@ void HistoryWidget::editDraftOptions() { .resolver = _preview->resolver(), .done = done, .highlight = highlight, - .clearOldDraft = [=] { ClearDraftReplyTo(history, replyToId); }, + .clearOldDraft = [=] { ClearDraftReplyTo(history, 0, replyToId); }, }); } 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 09eb7e76c..6fd788fd0 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -1332,6 +1332,7 @@ void ComposeControls::init() { _header->editOptionsRequests( ) | rpl::start_with_next([=] { const auto history = _history; + const auto topicRootId = _topicRootId; const auto reply = _header->replyingToMessage(); const auto webpage = _preview->draft(); @@ -1360,7 +1361,10 @@ void ComposeControls::init() { .resolver = _preview->resolver(), .done = done, .highlight = highlight, - .clearOldDraft = [=] { ClearDraftReplyTo(history, replyToId); }, + .clearOldDraft = [=] { ClearDraftReplyTo( + history, + topicRootId, + replyToId); }, }); }, _wrap->lifetime()); diff --git a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp index 30869de20..98799149f 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp @@ -400,13 +400,6 @@ void ForwardPanel::paint( }); } -void ClearDraftReplyTo(not_null thread, FullMsgId equalTo) { - ClearDraftReplyTo( - thread->owningHistory(), - thread->topicRootId(), - equalTo); -} - void ClearDraftReplyTo( not_null history, MsgId topicRootId, diff --git a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h index 7e3d2fac4..59c079d6f 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.h @@ -72,7 +72,6 @@ private: }; -void ClearDraftReplyTo(not_null thread, FullMsgId equalTo); void ClearDraftReplyTo( not_null history, MsgId topicRootId, diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 32983df4d..ead3dd294 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -330,6 +330,7 @@ RepliesWidget::RepliesWidget( Controls::ShowReplyToChatBox(controller->uiShow(), { fullId }); } else { replyToMessage(fullId); + _composeControls->focus(); } }, _inner->lifetime()); @@ -2016,7 +2017,7 @@ bool RepliesWidget::showMessage( } const auto id = FullMsgId(_history->peer->id, messageId); const auto message = _history->owner().message(id); - if (!message) { + if (!message || !message->inThread(_rootId)) { return false; } const auto originMessage = [&]() -> HistoryItem* { @@ -2032,11 +2033,10 @@ bool RepliesWidget::showMessage( } return nullptr; }(); - if (!originMessage) { - return false; - } const auto currentReplyReturn = _cornerButtons.replyReturn(); - const auto originItemId = (currentReplyReturn != originMessage) + const auto originItemId = !originMessage + ? FullMsgId() + : (currentReplyReturn != originMessage) ? originMessage->fullId() : FullMsgId(); showAtPosition(message->position(), originItemId, params); diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 6dc93b53a..148be7919 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 6dc93b53a1c4d237dea0a458d2b02c4171529f18 +Subproject commit 148be791963e32723056ae09de5f914f07df77b4 From 1341907cfd143df443d70fc2ebf7478fd1cce20c Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 10:50:17 +0400 Subject: [PATCH 09/44] Disable external replies for non-forwardable. --- .../history/history_inner_widget.cpp | 10 +--------- .../controls/history_view_draft_options.cpp | 18 ++++++++++-------- .../history/view/history_view_context_menu.cpp | 10 +--------- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 2adb08577..b831c8ea3 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -2391,15 +2391,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { : (Data::CanSendAnything(peer) && (!peer->isChannel() || peer->asChannel()->amIn())); }(); - const auto canReply = canSendReply || [&] { - const auto peer = item->history()->peer; - if (const auto chat = peer->asChat()) { - return !chat->isForbidden(); - } else if (const auto channel = peer->asChannel()) { - return !channel->isForbidden(); - } - return true; - }(); + const auto canReply = canSendReply || item->allowsForward(); if (canReply) { const auto itemId = item->fullId(); const auto quote = selectedQuote(item); diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp index 483a8d280..9b2b3f889 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp @@ -650,14 +650,16 @@ void DraftOptionsBox( const auto setupReplyActions = [=] { AddFilledSkip(bottom); - Settings::AddButton( - bottom, - tr::lng_reply_in_another_chat(), - st::settingsButton, - { &st::menuIconReplace } - )->setClickedCallback([=] { - ShowReplyToChatBox(show, resolveReply(), clearOldDraft); - }); + if (replyItem->allowsForward()) { + Settings::AddButton( + bottom, + tr::lng_reply_in_another_chat(), + st::settingsButton, + { &st::menuIconReplace } + )->setClickedCallback([=] { + ShowReplyToChatBox(show, resolveReply(), clearOldDraft); + }); + } Settings::AddButton( bottom, diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index 562069bc0..9ae59286b 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -592,15 +592,7 @@ bool AddReplyToMessageAction( const auto canSendReply = topic ? Data::CanSendAnything(topic) : Data::CanSendAnything(peer); - const auto canReply = canSendReply || [&] { - const auto peer = item->history()->peer; - if (const auto chat = peer->asChat()) { - return !chat->isForbidden(); - } else if (const auto channel = peer->asChannel()) { - return !channel->isForbidden(); - } - return true; - }(); + const auto canReply = canSendReply || item->allowsForward(); if (!canReply) { return false; } From 076291b98f2f013f4aa5ffad46a554446a8347ef Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 10:53:13 +0400 Subject: [PATCH 10/44] Fix reply invalidation on message removal. --- Telegram/SourceFiles/history/history_item_components.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 006bbced4..9ee8f0944 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -660,6 +660,8 @@ void HistoryMessageReply::clearData(not_null holder) { resolvedStory.get()); resolvedStory = nullptr; } + _name.clear(); + _text.clear(); _unavailable = 1; refreshReplyToMedia(); } From bde39970a076f0f9b59ef11bbd70b4523fe46b9c Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 11:17:55 +0400 Subject: [PATCH 11/44] Fix boost reassign. --- .../window/window_session_controller.cpp | 21 +++++++++++-------- .../window/window_session_controller.h | 2 ++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 3fbfd8145..b6822f2d4 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -685,6 +685,7 @@ void SessionNavigation::applyBoost( done(false); return; } + auto slot = int(); auto different = PeerId(); auto earliest = TimeId(-1); const auto now = base::unixtime::now(); @@ -695,13 +696,13 @@ void SessionNavigation::applyBoost( ? peerFromMTP(*data.vpeer()) : PeerId(); if (!peerId && cooldown <= now) { - applyBoostChecked(channel, done); + applyBoostChecked(channel, data.vslot().v, done); return; - } else if (peerId != channel->id) { + } else if (peerId != channel->id + && (earliest < 0 || cooldown < earliest)) { + slot = data.vslot().v; different = peerId; - if (earliest < 0 || cooldown < earliest) { - earliest = cooldown; - } + earliest = cooldown; } } if (different) { @@ -727,7 +728,7 @@ void SessionNavigation::applyBoost( done(false); } else { const auto peer = _session->data().peer(different); - replaceBoostConfirm(peer, channel, done); + replaceBoostConfirm(peer, channel, slot, done); } } else { uiShow()->show(Ui::MakeConfirmBox({ @@ -748,11 +749,12 @@ void SessionNavigation::applyBoost( void SessionNavigation::replaceBoostConfirm( not_null from, not_null channel, + int slot, Fn done) { const auto forwarded = std::make_shared(false); const auto confirmed = [=](Fn close) { *forwarded = true; - applyBoostChecked(channel, done); + applyBoostChecked(channel, slot, done); close(); }; const auto box = uiShow()->show(Box([=](not_null box) { @@ -781,10 +783,11 @@ void SessionNavigation::replaceBoostConfirm( void SessionNavigation::applyBoostChecked( not_null channel, + int slot, Fn done) { _api.request(MTPpremium_ApplyBoost( - MTP_flags(0), - MTPVector(), // slots + MTP_flags(MTPpremium_ApplyBoost::Flag::f_slots), + MTP_vector({ MTP_int(slot) }), channel->input )).done([=](const MTPpremium_MyBoosts &result) { done(true); diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 0bca576aa..2ae888937 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -318,9 +318,11 @@ private: void replaceBoostConfirm( not_null from, not_null channel, + int slot, Fn done); void applyBoostChecked( not_null channel, + int slot, Fn done); const not_null _session; From d831775e2f59ef96362f551a13abe709cfa974b2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 11:19:57 +0400 Subject: [PATCH 12/44] Fix replying in the same history. --- Telegram/SourceFiles/data/data_histories.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index fb5a116cc..e1fd60f6f 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -48,9 +48,17 @@ MTPInputReplyTo ReplyToForMTP( } } else if (replyTo.messageId || replyTo.topicRootId) { const auto to = LookupReplyTo(history, replyTo.messageId); + const auto replyingToTopicId = replyTo.topicRootId + ? replyTo.topicRootId + : Data::ForumTopic::kGeneralId; + const auto replyToTopicId = !to + ? replyingToTopicId + : to->topicRootId() + ? to->topicRootId() + : Data::ForumTopic::kGeneralId; const auto external = replyTo.messageId && (replyTo.messageId.peer != history->peer->id - || (replyTo.topicRootId != to->topicRootId())); + || replyingToTopicId != replyToTopicId); const auto quoteEntities = Api::EntitiesToMTP( &history->session(), replyTo.quote.entities, From b4c72723510f8769c9f926873203729b85113db1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 12:21:07 +0400 Subject: [PATCH 13/44] Keep external replies in forwards. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/history/history_item.cpp | 8 ++++++++ .../history/history_item_components.cpp | 15 ++++++++------- .../SourceFiles/history/history_item_components.h | 4 ++++ 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index ddfdafbde..183b86acd 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2685,6 +2685,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_reply_options_quote" = "Update Quote"; "lng_reply_header_short" = "Reply"; "lng_reply_quote_selected" = "Quote Selected"; +"lng_reply_from_private_chat" = "This reply is from a private chat."; "lng_link_options_header" = "Link Preview Settings"; "lng_link_header_short" = "Link"; "lng_link_move_up" = "Move Up"; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 7fd3fe5df..b4949c93f 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -449,6 +449,14 @@ HistoryItem::HistoryItem( const auto dropForwardInfo = original->computeDropForwardedInfo(); config.reply.messageId = config.reply.topMessageId = topicRootId; config.reply.topicPost = (topicRootId != 0); + if (const auto originalReply = original->Get()) { + if (originalReply->external()) { + config.reply = originalReply->fields(); + if (!config.reply.externalPeerId) { + config.reply.messageId = 0; + } + } + } if (!dropForwardInfo) { config.originalDate = original->originalDate(); if (const auto info = original->hiddenSenderInfo()) { diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 9ee8f0944..5dfadd9f6 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -397,9 +397,6 @@ ReplyFields ReplyFieldsFromMTP( auto result = ReplyFields(); if (const auto peer = data.vreply_to_peer_id()) { result.externalPeerId = peerFromMTP(*peer); - if (result.externalPeerId == history->peer->id) { - result.externalPeerId = 0; - } } const auto owner = &history->owner(); if (const auto id = data.vreply_to_msg_id().value_or_empty()) { @@ -526,8 +523,7 @@ bool HistoryMessageReply::updateData( } } - const auto external = _fields.externalSenderId - || !_fields.externalSenderName.isEmpty(); + const auto external = this->external(); if (resolvedMessage || resolvedStory || (external && (!_fields.messageId || force))) { @@ -625,9 +621,8 @@ void HistoryMessageReply::setLinkFrom( if (externalPeerId) { controller->showPeerInfo( controller->session().data().peer(externalPeerId)); - } else { - controller->showToast(u"External reply"_q); } + controller->showToast(tr::lng_reply_from_private_chat(tr::now)); } }; _link = resolvedMessage @@ -666,6 +661,12 @@ void HistoryMessageReply::clearData(not_null holder) { refreshReplyToMedia(); } +bool HistoryMessageReply::external() const { + return _fields.externalPeerId + || _fields.externalSenderId + || !_fields.externalSenderName.isEmpty(); +} + PeerData *HistoryMessageReply::sender(not_null holder) const { if (resolvedStory) { return resolvedStory->peer(); diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 2b5a90c57..c250e91fb 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -274,6 +274,7 @@ struct HistoryMessageReply // Must be called before destructor. void clearData(not_null holder); + [[nodiscard]] bool external() const; [[nodiscard]] PeerData *sender(not_null holder) const; [[nodiscard]] QString senderName(not_null holder) const; [[nodiscard]] QString senderName(not_null peer) const; @@ -301,6 +302,9 @@ struct HistoryMessageReply bool inBubble) const; void unloadPersistentAnimation(); + [[nodiscard]] ReplyFields fields() const { + return _fields; + } [[nodiscard]] PeerId externalPeerId() const { return _fields.externalPeerId; } From 6bab2b4df69dddb9d341737db424e90b2f490fe6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 12:59:32 +0400 Subject: [PATCH 14/44] Improve quotes composing. --- Telegram/lib_ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 148be7919..d7f12b083 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 148be791963e32723056ae09de5f914f07df77b4 +Subproject commit d7f12b083ee9901c5e5a95170559376d51b00f20 From 39614aab3f47f9bce6e17bf8db358aa39204a779 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 12:59:52 +0400 Subject: [PATCH 15/44] Fix unwrapped reply overlapping timestamp. --- .../history/view/media/history_view_media_unwrapped.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp index 413046ed3..69f4875e1 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp @@ -104,6 +104,9 @@ QSize UnwrappedMedia::countCurrentSize(int newWidth) { const auto surroundingWidth = _additionalOnTop ? std::min(newWidth - st::msgReplyPadding.left(), additional) : (newWidth - _contentSize.width() - st::msgReplyPadding.left()); + if (reply) { + [[maybe_unused]] auto h = reply->resizeToWidth(surroundingWidth); + } const auto surrounding = surroundingInfo(topic, via, reply, forwarded, surroundingWidth); if (_additionalOnTop) { _topAdded = surrounding.height + st::msgMargin.bottom(); From ade97fd2d23e67a83d2587d76feff83b8486485b Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 13:00:03 +0400 Subject: [PATCH 16/44] Fix unwrapped reply to monospace. --- Telegram/SourceFiles/ui/chat/chat.style | 1 + 1 file changed, 1 insertion(+) diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 0f1e19cde..70018cad1 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -146,6 +146,7 @@ outReplyTextPaletteSelected: TextPalette(outTextPaletteSelected) { } imgReplyTextPalette: TextPalette(defaultTextPalette) { linkFg: msgImgReplyBarColor; + monoFg: msgImgReplyBarColor; } inSemiboldPalette: TextPalette(inTextPalette) { linkFg: msgInServiceFg; From 46d3f232af1721c7f9cc76e2e5b22a3b11fbc3d7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 13:08:32 +0400 Subject: [PATCH 17/44] Don't drop reply info on empty message submit. --- Telegram/SourceFiles/history/history_widget.cpp | 9 ++++++++- Telegram/SourceFiles/history/history_widget.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 289438e5b..b0e5f8d2a 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -842,7 +842,9 @@ HistoryWidget::HistoryWidget( }); } else { fastShowAtEnd(action.history); - if (cancelReply(lastKeyboardUsed) && !action.clearDraft) { + if (!_justMarkingAsRead + && cancelReply(lastKeyboardUsed) + && !action.clearDraft) { saveCloudDraft(); } } @@ -3963,7 +3965,12 @@ void HistoryWidget::send(Api::SendOptions options) { ignoreSlowmodeCountdown)) { return; } + + // Just a flag not to drop reply info if we're not sending anything. + _justMarkingAsRead = !HasSendText(_field) + && message.webPage.url.isEmpty(); session().api().sendMessage(std::move(message)); + _justMarkingAsRead = false; clearFieldText(); if (_preview) { diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 450985010..ebc1a04c8 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -812,6 +812,7 @@ private: int _itemsRevealHeight = 0; bool _sponsoredMessagesStateKnown = false; + bool _justMarkingAsRead = false; object_ptr _topShadow; bool _inGrab = false; From bf20dbe3bc073b7b4eed246ce3c8412c22c82506 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 13:13:31 +0400 Subject: [PATCH 18/44] Fix external replies to different topic groups. --- Telegram/SourceFiles/apiwrap.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 990678304..02e3bb9c1 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -3579,14 +3579,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) { action.generateLocal = true; sendAction(action); - const auto replyTo = action.replyTo.messageId - ? peer->owner().message(action.replyTo.messageId) - : nullptr; - const auto topicRootId = replyTo - ? replyTo->topicRootId() - : action.replyTo.topicRootId - ? action.replyTo.topicRootId - : Data::ForumTopic::kGeneralId; + const auto clearCloudDraft = action.clearDraft; + const auto topicRootId = action.replyTo.topicRootId; const auto topic = peer->forumTopicFor(topicRootId); if (!(topic ? Data::CanSendTexts(topic) : Data::CanSendTexts(peer)) || Api::SendDice(message)) { @@ -3682,8 +3676,6 @@ void ApiWrap::sendMessage(MessageToSend &&message) { sendFlags |= MTPmessages_SendMessage::Flag::f_entities; mediaFlags |= MTPmessages_SendMedia::Flag::f_entities; } - const auto clearCloudDraft = action.clearDraft; - const auto topicRootId = action.replyTo.topicRootId; if (clearCloudDraft) { sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft; mediaFlags |= MTPmessages_SendMedia::Flag::f_clear_draft; From 1cfda38345fe98171cf2b9ac98a1df94dee68ccc Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 13:20:30 +0400 Subject: [PATCH 19/44] Fix reply in topic after creation. --- .../view/controls/history_view_compose_controls.cpp | 10 ++++++++++ .../view/controls/history_view_compose_controls.h | 1 + .../history/view/history_view_replies_section.cpp | 1 + 3 files changed, 12 insertions(+) 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 6fd788fd0..43f505b6b 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -112,6 +112,7 @@ public: std::shared_ptr show); void setHistory(const SetHistoryArgs &args); + void updateTopicRootId(MsgId topicRootId); void init(); void editMessage(FullMsgId id, bool photoEditAllowed = false); @@ -229,6 +230,10 @@ void FieldHeader::setHistory(const SetHistoryArgs &args) { _topicRootId = args.topicRootId; } +void FieldHeader::updateTopicRootId(MsgId topicRootId) { + _topicRootId = topicRootId; +} + void FieldHeader::init() { sizeValue( ) | rpl::start_with_next([=](QSize size) { @@ -855,6 +860,11 @@ Main::Session &ComposeControls::session() const { return _show->session(); } +void ComposeControls::updateTopicRootId(MsgId topicRootId) { + _topicRootId = topicRootId; + _header->updateTopicRootId(_topicRootId); +} + void ComposeControls::setHistory(SetHistoryArgs &&args) { _showSlowmodeError = std::move(args.showSlowmodeError); _sendActionFactory = std::move(args.sendActionFactory); 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 18a76132e..be07fd1b5 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -135,6 +135,7 @@ public: [[nodiscard]] Main::Session &session() const; void setHistory(SetHistoryArgs &&args); + void updateTopicRootId(MsgId topicRootId); void setCurrentDialogsEntryState(Dialogs::EntryState state); [[nodiscard]] PeerData *sendAsPeer() const; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index ead3dd294..8789099ea 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -493,6 +493,7 @@ void RepliesWidget::setupTopicViewer() { ) | rpl::start_with_next([=](const Data::Session::IdChange &change) { if (_rootId == change.oldId) { _rootId = change.newId.msg; + _composeControls->updateTopicRootId(_rootId); _sendAction = owner->sendActionManager().repliesPainter( _history, _rootId); From 6493cb9ed8f23fc2136134dbb5b883827140992c Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 31 Oct 2023 13:05:51 +0300 Subject: [PATCH 20/44] Fixed mouse wheel handling in vertical drum picker without animation. --- .../ui/widgets/vertical_drum_picker.cpp | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/ui/widgets/vertical_drum_picker.cpp b/Telegram/SourceFiles/ui/widgets/vertical_drum_picker.cpp index 9e546e004..d0cc71ca3 100644 --- a/Telegram/SourceFiles/ui/widgets/vertical_drum_picker.cpp +++ b/Telegram/SourceFiles/ui/widgets/vertical_drum_picker.cpp @@ -11,6 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_basic.h" namespace Ui { +namespace { + +constexpr auto kAlmostIndex = float64(.99); + +} // namespace PickerAnimation::PickerAnimation() = default; @@ -26,6 +31,23 @@ void PickerAnimation::jumpToOffset(int offset) { value); _updates.fire(_result.current - was); }; + if (anim::Disabled()) { + auto value = float64(0.); + const auto diff = _result.to - _result.from; + const auto step = std::min( + kAlmostIndex, + 1. / (std::max(1. - kAlmostIndex, std::abs(diff) + 1))); + while (true) { + value += step; + if (value >= 1.) { + callback(1.); + break; + } else { + callback(value); + } + } + return; + } _animation.start( std::move(callback), 0., @@ -94,20 +116,14 @@ VerticalDrumPicker::VerticalDrumPicker( }, lifetime()); _animation.updates( - ) | rpl::distinct_until_changed( ) | rpl::start_with_next([=](PickerAnimation::Shift shift) { increaseShift(shift); - if (anim::Disabled()) { - animationDataFromIndex(); - _animation.jumpToOffset(0); - } }, lifetime()); } void VerticalDrumPicker::increaseShift(float64 by) { { // Guard input. - constexpr auto kAlmostIndex = .99; if (by >= 1.) { by = kAlmostIndex; } else if (by <= -1.) { From 0dbb195106fb81e546c5f06c9f8b8e5f76af1e48 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 22:37:59 +0400 Subject: [PATCH 21/44] Highlight quotes in replies to albums. --- .../history/history_inner_widget.cpp | 14 +- .../history/history_inner_widget.h | 3 +- .../history_view_highlight_manager.cpp | 57 +++++-- .../history/history_view_highlight_manager.h | 8 +- .../SourceFiles/history/history_widget.cpp | 5 +- Telegram/SourceFiles/history/history_widget.h | 2 +- .../controls/history_view_draft_options.cpp | 8 +- .../history/view/history_view_context_menu.h | 1 + .../history/view/history_view_element.cpp | 135 +++++++++++++++++ .../history/view/history_view_element.h | 26 +++- .../history/view/history_view_list_widget.cpp | 17 +-- .../history/view/history_view_list_widget.h | 2 +- .../history/view/history_view_message.cpp | 143 +----------------- .../history/view/history_view_message.h | 9 +- .../view/history_view_service_message.cpp | 15 +- .../view/history_view_service_message.h | 9 +- .../view/media/history_view_document.cpp | 11 +- .../view/media/history_view_document.h | 3 +- .../history/view/media/history_view_gif.cpp | 7 +- .../history/view/media/history_view_gif.h | 3 +- .../history/view/media/history_view_media.cpp | 4 + .../history/view/media/history_view_media.h | 8 +- .../view/media/history_view_media_grouped.cpp | 97 ++++++++++-- .../view/media/history_view_media_grouped.h | 4 + .../history/view/media/history_view_photo.cpp | 7 +- .../history/view/media/history_view_photo.h | 3 +- 26 files changed, 364 insertions(+), 237 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index b831c8ea3..552905840 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -2106,7 +2106,7 @@ void HistoryInner::toggleFavoriteReaction(not_null view) const { item->toggleReaction(favorite, HistoryItem::ReactionSource::Quick); } -TextWithEntities HistoryInner::selectedQuote( +HistoryView::SelectedQuote HistoryInner::selectedQuote( not_null item) const { if (_selected.size() != 1 || _selected.begin()->first != item @@ -2393,11 +2393,13 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { }(); const auto canReply = canSendReply || item->allowsForward(); if (canReply) { - const auto itemId = item->fullId(); - const auto quote = selectedQuote(item); - auto text = quote.empty() - ? tr::lng_context_reply_msg(tr::now) - : tr::lng_context_quote_and_reply(tr::now); + const auto selected = selectedQuote(item); + auto text = selected + ? tr::lng_context_quote_and_reply(tr::now) + : tr::lng_context_reply_msg(tr::now); + const auto replyToItem = selected.item ? selected.item : item; + const auto itemId = replyToItem->fullId(); + const auto quote = selected.text; text.replace('&', u"&&"_q); _menu->addAction(text, [=] { if (canSendReply) { diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index c6049a844..810521f50 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -35,6 +35,7 @@ class EmptyPainter; class Element; class TranslateTracker; struct PinnedId; +struct SelectedQuote; } // namespace HistoryView namespace HistoryView::Reactions { @@ -314,7 +315,7 @@ private: QPoint mapPointToItem(QPoint p, const Element *view) const; QPoint mapPointToItem(QPoint p, const HistoryItem *item) const; - [[nodiscard]] TextWithEntities selectedQuote( + [[nodiscard]] HistoryView::SelectedQuote selectedQuote( not_null item) const; void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false); diff --git a/Telegram/SourceFiles/history/history_view_highlight_manager.cpp b/Telegram/SourceFiles/history/history_view_highlight_manager.cpp index 94244ef00..29e157344 100644 --- a/Telegram/SourceFiles/history/history_view_highlight_manager.cpp +++ b/Telegram/SourceFiles/history/history_view_highlight_manager.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_view_highlight_manager.h" #include "data/data_session.h" +#include "history/history.h" #include "history/history_item.h" #include "history/view/history_view_element.h" #include "ui/chat/chat_style.h" @@ -26,17 +27,22 @@ ElementHighlighter::ElementHighlighter( void ElementHighlighter::enqueue( not_null view, - TextSelection part) { - const auto item = view->data(); - const auto data = Highlight{ item->fullId(), part }; + const TextWithEntities &part) { + const auto data = computeHighlight(view, part); if (_queue.empty() && !_animation.animating()) { - highlight(data.itemId, data.part); + highlight(data); } else if (_highlighted != data && !base::contains(_queue, data)) { _queue.push_back(data); checkNextHighlight(); } } +void ElementHighlighter::highlight( + not_null view, + const TextWithEntities &part) { + highlight(computeHighlight(view, part)); +} + void ElementHighlighter::checkNextHighlight() { if (_animation.animating()) { return; @@ -53,10 +59,9 @@ void ElementHighlighter::checkNextHighlight() { } return Highlight(); }(); - if (!next) { - return; + if (next) { + highlight(next); } - highlight(next.itemId, next.part); } Ui::ChatPaintHighlight ElementHighlighter::state( @@ -69,18 +74,46 @@ Ui::ChatPaintHighlight ElementHighlighter::state( return {}; } -void ElementHighlighter::highlight(FullMsgId itemId, TextSelection part) { - if (const auto item = _data->message(itemId)) { +ElementHighlighter::Highlight ElementHighlighter::computeHighlight( + not_null view, + const TextWithEntities &part) { + const auto item = view->data(); + const auto owner = &item->history()->owner(); + if (const auto group = owner->groups().find(item)) { + const auto leader = group->items.front(); + const auto leaderId = leader->fullId(); + const auto i = ranges::find(group->items, item); + if (i != end(group->items)) { + const auto index = int(i - begin(group->items)); + if (part.empty()) { + return { leaderId, AddGroupItemSelection({}, index) }; + } else if (const auto leaderView = _viewForItem(leader)) { + return { + leaderId, + leaderView->selectionFromQuote(item, part), + }; + } + } + return { leaderId }; + } else if (part.empty()) { + return { item->fullId() }; + } + return { item->fullId(), view->selectionFromQuote(item, part) }; +} + +void ElementHighlighter::highlight(Highlight data) { + if (const auto item = _data->message(data.itemId)) { if (const auto view = _viewForItem(item)) { - if (_highlighted && _highlighted.itemId != itemId) { + if (_highlighted && _highlighted.itemId != data.itemId) { if (const auto was = _data->message(_highlighted.itemId)) { if (const auto view = _viewForItem(was)) { repaintHighlightedItem(view); } } } - _highlighted = { itemId, part }; - _animation.start(!part.empty()); + _highlighted = data; + _animation.start(!data.part.empty() + && !IsSubGroupSelection(data.part)); repaintHighlightedItem(view); } diff --git a/Telegram/SourceFiles/history/history_view_highlight_manager.h b/Telegram/SourceFiles/history/history_view_highlight_manager.h index f6de65ceb..7d74ed9a5 100644 --- a/Telegram/SourceFiles/history/history_view_highlight_manager.h +++ b/Telegram/SourceFiles/history/history_view_highlight_manager.h @@ -33,8 +33,8 @@ public: ViewForItem viewForItem, RepaintView repaintView); - void enqueue(not_null view, TextSelection part); - void highlight(FullMsgId itemId, TextSelection part); + void enqueue(not_null view, const TextWithEntities &part); + void highlight(not_null view, const TextWithEntities &part); void clear(); [[nodiscard]] Ui::ChatPaintHighlight state( @@ -72,6 +72,10 @@ private: friend inline bool operator==(Highlight, Highlight) = default; }; + [[nodiscard]] Highlight computeHighlight( + not_null view, + const TextWithEntities &part); + void highlight(Highlight data); void checkNextHighlight(); void repaintHighlightedItem(not_null view); void updateMessage(); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index b0e5f8d2a..de130e3c1 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1270,7 +1270,7 @@ void HistoryWidget::scrollToAnimationCallback( void HistoryWidget::enqueueMessageHighlight( not_null view, - TextSelection part) { + const TextWithEntities &part) { _highlighter.enqueue(view, part); } @@ -5709,8 +5709,7 @@ int HistoryWidget::countInitialScrollTop() { enqueueMessageHighlight( view, - view->selectionFromQuote( - base::take(_showAtMsgHighlightPart))); + base::take(_showAtMsgHighlightPart)); const auto result = itemTopForHighlight(view); createUnreadBarIfBelowVisibleArea(result); return result; diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index ebc1a04c8..4bf971ff2 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -184,7 +184,7 @@ public: void enqueueMessageHighlight( not_null view, - TextSelection part); + const TextWithEntities &part); [[nodiscard]] Ui::ChatPaintHighlight itemHighlight( not_null item) const; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp index 9b2b3f889..9a4b2ba53 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp @@ -217,7 +217,9 @@ rpl::producer PreviewWrap::showQuoteSelector( const TextWithEntities "e) { _selection.reset(TextSelection()); - _element = item->createView(_delegate.get()); + const auto group = item->history()->owner().groups().find(item); + const auto leader = group ? group->items.front() : item; + _element = leader->createView(_delegate.get()); _link = _pressedLink = nullptr; if (const auto was = base::take(_draftItem)) { @@ -233,10 +235,10 @@ rpl::producer PreviewWrap::showQuoteSelector( initElement(); - _selection = _element->selectionFromQuote(quote); + _selection = _element->selectionFromQuote(item, quote); return _selection.value( ) | rpl::map([=](TextSelection selection) { - return _element->selectedQuote(selection); + return _element->selectedQuote(selection).text; }); } diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.h b/Telegram/SourceFiles/history/view/history_view_context_menu.h index 64040ae41..fb99d2cc6 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.h +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.h @@ -48,6 +48,7 @@ struct ContextMenuRequest { SelectedItems selectedItems; TextForMimeData selectedText; TextWithEntities quote; + HistoryItem *quoteItem = nullptr; bool overSelection = false; PointState pointState = PointState(); }; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index ac3cf2ad2..68f8c49ad 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -94,6 +94,42 @@ Element *MousedElement/* = nullptr*/; return session->tryResolveWindow(); } +[[nodiscard]] bool CheckQuoteEntities( + const EntitiesInText "eEntities, + const TextWithEntities &original, + TextSelection selection) { + auto left = quoteEntities; + const auto allowed = std::array{ + EntityType::Bold, + EntityType::Italic, + EntityType::Underline, + EntityType::StrikeOut, + EntityType::Spoiler, + EntityType::CustomEmoji, + }; + for (const auto &entity : original.entities) { + const auto from = entity.offset(); + const auto till = from + entity.length(); + if (till <= selection.from || from >= selection.to) { + continue; + } + const auto quoteFrom = std::max(from, int(selection.from)); + const auto quoteTill = std::min(till, int(selection.to)); + const auto cut = EntityInText( + entity.type(), + quoteFrom - int(selection.from), + quoteTill - quoteFrom, + entity.data()); + const auto i = ranges::find(left, cut); + if (i != left.end()) { + left.erase(i); + } else if (ranges::contains(allowed, cut.type())) { + return false; + } + } + return left.empty(); +}; + } // namespace std::unique_ptr MakePathShiftGradient( @@ -1559,6 +1595,105 @@ TextSelection Element::adjustSelection( return selection; } +SelectedQuote Element::FindSelectedQuote( + const Ui::Text::String &text, + TextSelection selection, + not_null item) { + if (selection.to > text.length()) { + return {}; + } + auto modified = selection; + for (const auto &modification : text.modifications()) { + if (modification.position >= selection.to) { + break; + } else if (modification.position <= selection.from) { + modified.from += modification.skipped; + if (modification.added + && modification.position < selection.from) { + --modified.from; + } + } + modified.to += modification.skipped; + if (modification.added && modified.to > modified.from) { + --modified.to; + } + } + auto result = item->originalText(); + if (modified.empty() || modified.to > result.text.size()) { + return {}; + } + result.text = result.text.mid( + modified.from, + modified.to - modified.from); + const auto allowed = std::array{ + EntityType::Bold, + EntityType::Italic, + EntityType::Underline, + EntityType::StrikeOut, + EntityType::Spoiler, + EntityType::CustomEmoji, + }; + for (auto i = result.entities.begin(); i != result.entities.end();) { + const auto offset = i->offset(); + const auto till = offset + i->length(); + if ((till <= modified.from) + || (offset >= modified.to) + || !ranges::contains(allowed, i->type())) { + i = result.entities.erase(i); + } else { + if (till > modified.to) { + i->shrinkFromRight(till - modified.to); + } + i->shiftLeft(modified.from); + ++i; + } + } + return { item, result }; +} + +TextSelection Element::FindSelectionFromQuote( + const Ui::Text::String &text, + not_null item, + const TextWithEntities "e) { + if (quote.empty()) { + return {}; + } + const auto &original = item->originalText(); + auto result = TextSelection(); + auto offset = 0; + while (true) { + const auto i = original.text.indexOf(quote.text, offset); + if (i < 0) { + return {}; + } + auto selection = TextSelection{ + uint16(i), + uint16(i + quote.text.size()), + }; + if (CheckQuoteEntities(quote.entities, original, selection)) { + result = selection; + break; + } + offset = i + 1; + } + //for (const auto &modification : text.modifications()) { + // if (modification.position >= selection.to) { + // break; + // } else if (modification.position <= selection.from) { + // modified.from += modification.skipped; + // if (modification.added + // && modification.position < selection.from) { + // --modified.from; + // } + // } + // modified.to += modification.skipped; + // if (modification.added && modified.to > modified.from) { + // --modified.to; + // } + //} + return result; +} + Reactions::ButtonParameters Element::reactionButtonParameters( QPoint position, const TextState &reactionState) const { diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index fa8e9e4fa..8261628d7 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -266,6 +266,15 @@ struct TopicButton { int nameVersion = 0; }; +struct SelectedQuote { + HistoryItem *item = nullptr; + TextWithEntities text; + + explicit operator bool() const { + return item && !text.empty(); + } +}; + class Element : public Object , public RuntimeComposer @@ -387,19 +396,24 @@ public: QPoint point, InfoDisplayType type) const; virtual TextForMimeData selectedText(TextSelection selection) const = 0; - virtual TextWithEntities selectedQuote(TextSelection selection) const = 0; - virtual TextWithEntities selectedQuote( - const Ui::Text::String &text, + virtual SelectedQuote selectedQuote( TextSelection selection) const = 0; virtual TextSelection selectionFromQuote( - const TextWithEntities "e) const = 0; - virtual TextSelection selectionFromQuote( - const Ui::Text::String &text, + not_null item, const TextWithEntities "e) const = 0; [[nodiscard]] virtual TextSelection adjustSelection( TextSelection selection, TextSelectType type) const; + [[nodiscard]] static SelectedQuote FindSelectedQuote( + const Ui::Text::String &text, + TextSelection selection, + not_null item); + [[nodiscard]] static TextSelection FindSelectionFromQuote( + const Ui::Text::String &text, + not_null item, + const TextWithEntities "e); + [[nodiscard]] virtual auto reactionButtonParameters( QPoint position, const TextState &reactionState) const -> Reactions::ButtonParameters; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 07f63ce4f..28932369a 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -709,13 +709,10 @@ bool ListWidget::isBelowPosition(Data::MessagePosition position) const { void ListWidget::highlightMessage( FullMsgId itemId, - const TextWithEntities &highlightPart) { - const auto view = !highlightPart.empty() - ? viewForItem(itemId) - : nullptr; - _highlighter.highlight( - itemId, - view ? view->selectionFromQuote(highlightPart) : TextSelection()); + const TextWithEntities &part) { + if (const auto view = viewForItem(itemId)) { + _highlighter.highlight(view, part); + } } void ListWidget::showAroundPosition( @@ -2607,9 +2604,11 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { request.view = _overElement; request.item = overItem; request.pointState = _overState.pointState; - request.quote = (overItemView && _selectedTextItem == overItem) + const auto quote = (overItemView && _selectedTextItem == overItem) ? overItemView->selectedQuote(_selectedTextRange) - : TextWithEntities(); + : SelectedQuote(); + request.quote = quote.text; + request.quoteItem = quote.item; request.selectedText = _selectedText; request.selectedItems = collectSelectedItems(); const auto hasSelection = !request.selectedItems.empty() diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index fd56b9313..95b641a04 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -233,7 +233,7 @@ public: bool isBelowPosition(Data::MessagePosition position) const; void highlightMessage( FullMsgId itemId, - const TextWithEntities &highlightPart); + const TextWithEntities &part); void showAtPosition( Data::MessagePosition position, diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index cf2d82973..a73b2e18c 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -65,42 +65,6 @@ const auto kPsaTooltipPrefix = "cloud_lng_tooltip_psa_"; return std::nullopt; } -[[nodiscard]] bool CheckQuoteEntities( - const EntitiesInText "eEntities, - const TextWithEntities &original, - TextSelection selection) { - auto left = quoteEntities; - const auto allowed = std::array{ - EntityType::Bold, - EntityType::Italic, - EntityType::Underline, - EntityType::StrikeOut, - EntityType::Spoiler, - EntityType::CustomEmoji, - }; - for (const auto &entity : original.entities) { - const auto from = entity.offset(); - const auto till = from + entity.length(); - if (till <= selection.from || from >= selection.to) { - continue; - } - const auto quoteFrom = std::max(from, int(selection.from)); - const auto quoteTill = std::min(till, int(selection.to)); - const auto cut = EntityInText( - entity.type(), - quoteFrom - int(selection.from), - quoteTill - quoteFrom, - entity.data()); - const auto i = ranges::find(left, cut); - if (i != left.end()) { - left.erase(i); - } else if (ranges::contains(allowed, cut.type())) { - return false; - } - } - return left.empty(); -}; - class KeyboardStyle : public ReplyKeyboard::Style { public: KeyboardStyle(const style::BotKeyboardButton &st); @@ -2682,7 +2646,7 @@ TextForMimeData Message::selectedText(TextSelection selection) const { return result; } -TextWithEntities Message::selectedQuote(TextSelection selection) const { +SelectedQuote Message::selectedQuote(TextSelection selection) const { const auto item = data(); const auto &translated = item->translatedText(); const auto &original = item->originalText(); @@ -2697,7 +2661,7 @@ TextWithEntities Message::selectedQuote(TextSelection selection) const { const auto textSelection = mediaBefore ? media->skipSelection(selection) : selection; - return selectedQuote(text(), textSelection); + return FindSelectedQuote(text(), textSelection, data()); } else if (const auto media = this->media()) { if (media->isDisplayed() || isHiddenByGroup()) { return media->selectedQuote(selection); @@ -2706,67 +2670,12 @@ TextWithEntities Message::selectedQuote(TextSelection selection) const { return {}; } -TextWithEntities Message::selectedQuote( - const Ui::Text::String &text, - TextSelection selection) const { - if (selection.to > text.length()) { - return {}; - } - auto modified = selection; - for (const auto &modification : text.modifications()) { - if (modification.position >= selection.to) { - break; - } else if (modification.position <= selection.from) { - modified.from += modification.skipped; - if (modification.added - && modification.position < selection.from) { - --modified.from; - } - } - modified.to += modification.skipped; - if (modification.added && modified.to > modified.from) { - --modified.to; - } - } - auto result = data()->originalText(); - if (modified.empty() || modified.to > result.text.size()) { - return {}; - } - result.text = result.text.mid( - modified.from, - modified.to - modified.from); - const auto allowed = std::array{ - EntityType::Bold, - EntityType::Italic, - EntityType::Underline, - EntityType::StrikeOut, - EntityType::Spoiler, - EntityType::CustomEmoji, - }; - for (auto i = result.entities.begin(); i != result.entities.end();) { - const auto offset = i->offset(); - const auto till = offset + i->length(); - if ((till <= modified.from) - || (offset >= modified.to) - || !ranges::contains(allowed, i->type())) { - i = result.entities.erase(i); - } else { - if (till > modified.to) { - i->shrinkFromRight(till - modified.to); - } - i->shiftLeft(modified.from); - ++i; - } - } - return result; -} - TextSelection Message::selectionFromQuote( + not_null item, const TextWithEntities "e) const { if (quote.empty()) { return {}; } - const auto item = data(); const auto &translated = item->translatedText(); const auto &original = item->originalText(); if (&translated != &original) { @@ -2775,58 +2684,16 @@ TextSelection Message::selectionFromQuote( const auto media = this->media(); const auto mediaDisplayed = media && media->isDisplayed(); const auto mediaBefore = mediaDisplayed && invertMedia(); - const auto result = selectionFromQuote(text(), quote); + const auto result = FindSelectionFromQuote(text(), item, quote); return mediaBefore ? media->unskipSelection(result) : result; } else if (const auto media = this->media()) { if (media->isDisplayed() || isHiddenByGroup()) { - return media->selectionFromQuote(quote); + return media->selectionFromQuote(item, quote); } } return {}; } -TextSelection Message::selectionFromQuote( - const Ui::Text::String &text, - const TextWithEntities "e) const { - if (quote.empty()) { - return {}; - } - const auto &original = data()->originalText(); - auto result = TextSelection(); - auto offset = 0; - while (true) { - const auto i = original.text.indexOf(quote.text, offset); - if (i < 0) { - return {}; - } - auto selection = TextSelection{ - uint16(i), - uint16(i + quote.text.size()), - }; - if (CheckQuoteEntities(quote.entities, original, selection)) { - result = selection; - break; - } - offset = i + 1; - } - //for (const auto &modification : text.modifications()) { - // if (modification.position >= selection.to) { - // break; - // } else if (modification.position <= selection.from) { - // modified.from += modification.skipped; - // if (modification.added - // && modification.position < selection.from) { - // --modified.from; - // } - // } - // modified.to += modification.skipped; - // if (modification.added && modified.to > modified.from) { - // --modified.to; - // } - //} - return result; -} - TextSelection Message::adjustSelection( TextSelection selection, TextSelectType type) const { diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h index 7506bf355..aa66b0cf5 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.h +++ b/Telegram/SourceFiles/history/view/history_view_message.h @@ -95,14 +95,9 @@ public: QPoint point, InfoDisplayType type) const override; TextForMimeData selectedText(TextSelection selection) const override; - TextWithEntities selectedQuote(TextSelection selection) const override; - TextWithEntities selectedQuote( - const Ui::Text::String &text, - TextSelection selection) const override; + SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( - const TextWithEntities "e) const override; - TextSelection selectionFromQuote( - const Ui::Text::String &text, + not_null item, const TextWithEntities "e) const override; TextSelection adjustSelection( TextSelection selection, diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.cpp b/Telegram/SourceFiles/history/view/history_view_service_message.cpp index a3d6550c5..0705ff2a5 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_service_message.cpp @@ -669,23 +669,12 @@ TextForMimeData Service::selectedText(TextSelection selection) const { return text().toTextForMimeData(selection); } -TextWithEntities Service::selectedQuote(TextSelection selection) const { - return {}; -} - -TextWithEntities Service::selectedQuote( - const Ui::Text::String &text, - TextSelection selection) const { +SelectedQuote Service::selectedQuote(TextSelection selection) const { return {}; } TextSelection Service::selectionFromQuote( - const TextWithEntities "e) const { - return {}; -} - -TextSelection Service::selectionFromQuote( - const Ui::Text::String &text, + not_null item, const TextWithEntities "e) const { return {}; } diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.h b/Telegram/SourceFiles/history/view/history_view_service_message.h index c862ce657..617dd1adb 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.h +++ b/Telegram/SourceFiles/history/view/history_view_service_message.h @@ -43,14 +43,9 @@ public: StateRequest request) const override; void updatePressed(QPoint point) override; TextForMimeData selectedText(TextSelection selection) const override; - TextWithEntities selectedQuote(TextSelection selection) const override; - TextWithEntities selectedQuote( - const Ui::Text::String &text, - TextSelection selection) const override; + SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( - const TextWithEntities "e) const override; - TextSelection selectionFromQuote( - const Ui::Text::String &text, + not_null item, const TextWithEntities "e) const override; TextSelection adjustSelection( TextSelection selection, diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 7346966da..7530b31ff 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -1212,7 +1212,7 @@ TextForMimeData Document::selectedText(TextSelection selection) const { return result; } -TextWithEntities Document::selectedQuote(TextSelection selection) const { +SelectedQuote Document::selectedQuote(TextSelection selection) const { if (const auto voice = Get()) { const auto length = voice->transcribeText.length(); if (selection.from < length) { @@ -1223,16 +1223,21 @@ TextWithEntities Document::selectedQuote(TextSelection selection) const { voice->transcribeText); } if (const auto captioned = Get()) { - return parent()->selectedQuote(captioned->caption, selection); + return Element::FindSelectedQuote( + captioned->caption, + selection, + _realParent); } return {}; } TextSelection Document::selectionFromQuote( + not_null item, const TextWithEntities "e) const { if (const auto captioned = Get()) { - const auto result = parent()->selectionFromQuote( + const auto result = Element::FindSelectionFromQuote( captioned->caption, + item, quote); if (result.empty()) { return {}; diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.h b/Telegram/SourceFiles/history/view/media/history_view_document.h index 31dd9886a..ec2dc0d78 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.h +++ b/Telegram/SourceFiles/history/view/media/history_view_document.h @@ -46,8 +46,9 @@ public: bool hasTextForCopy() const override; TextForMimeData selectedText(TextSelection selection) const override; - TextWithEntities selectedQuote(TextSelection selection) const override; + SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( + not_null item, const TextWithEntities "e) const override; bool uploading() const override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index d35658d88..340b1fa66 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -1205,13 +1205,14 @@ TextForMimeData Gif::selectedText(TextSelection selection) const { return _caption.toTextForMimeData(selection); } -TextWithEntities Gif::selectedQuote(TextSelection selection) const { - return parent()->selectedQuote(_caption, selection); +SelectedQuote Gif::selectedQuote(TextSelection selection) const { + return Element::FindSelectedQuote(_caption, selection, _realParent); } TextSelection Gif::selectionFromQuote( + not_null item, const TextWithEntities "e) const { - return parent()->selectionFromQuote(_caption, quote); + return Element::FindSelectionFromQuote(_caption, item, quote); } bool Gif::fullFeaturedGrouped(RectParts sides) const { diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h index fdba9a0af..eac33cc7a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.h +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h @@ -68,8 +68,9 @@ public: } TextForMimeData selectedText(TextSelection selection) const override; - TextWithEntities selectedQuote(TextSelection selection) const override; + SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( + not_null item, const TextWithEntities "e) const override; bool uploading() const override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.cpp b/Telegram/SourceFiles/history/view/media/history_view_media.cpp index 4e19fa291..69cad0ec4 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media.cpp @@ -189,6 +189,10 @@ not_null Media::history() const { return _parent->history(); } +SelectedQuote Media::selectedQuote(TextSelection selection) const { + return {}; +} + bool Media::isDisplayed() const { return true; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.h b/Telegram/SourceFiles/history/view/media/history_view_media.h index bda57224e..392806575 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media.h @@ -49,6 +49,7 @@ struct StateRequest; struct MediaSpoiler; class StickerPlayer; class Element; +struct SelectedQuote; using PaintContext = Ui::ChatPaintContext; @@ -88,11 +89,10 @@ public: TextSelection selection) const { return {}; } - [[nodiscard]] virtual TextWithEntities selectedQuote( - TextSelection selection) const { - return {}; - } + [[nodiscard]] virtual SelectedQuote selectedQuote( + TextSelection selection) const; [[nodiscard]] virtual TextSelection selectionFromQuote( + not_null item, const TextWithEntities "e) const { return {}; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp index 37676611d..9766c5aaa 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp @@ -286,16 +286,44 @@ void GroupedMedia::drawHighlight( Painter &p, const PaintContext &context, int top) const { + auto selection = context.highlight.range; if (_mode != Mode::Column) { + if (!selection.empty() && !IsSubGroupSelection(selection)) { + _parent->paintCustomHighlight( + p, + context, + top, + height(), + _parent->data().get()); + } return; } + const auto empty = selection.empty(); + const auto subpart = IsSubGroupSelection(selection); const auto skip = top + groupedPadding().top(); for (auto i = 0, count = int(_parts.size()); i != count; ++i) { const auto &part = _parts[i]; const auto rect = part.geometry.translated(0, skip); + const auto full = (!i && empty) + || (subpart && IsGroupItemSelection(selection, i)); + auto copy = context; + if (full) { + copy.highlight.range = {}; + _parent->paintCustomHighlight( + p, + copy, + rect.y(), + rect.height(), + part.item); + } else if (!selection.empty()) { + copy.highlight.range = selection; + selection = part.content->skipSelection(selection); + } else { + break; + } _parent->paintCustomHighlight( p, - context, + copy, rect.y(), rect.height(), part.item); @@ -316,6 +344,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { const auto rounding = inWebPage ? Ui::BubbleRounding{ kSmall, kSmall, kSmall, kSmall } : adjustedBubbleRoundingWithCaption(_caption); + const auto highlight = context.highlight.range; for (auto i = 0, count = int(_parts.size()); i != count; ++i) { const auto &part = _parts[i]; const auto partContext = context.withSelection(fullSelection @@ -325,10 +354,11 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { : IsGroupItemSelection(selection, i) ? FullSelection : TextSelection()); - const auto highlightOpacity = IsGroupItemSelection( - context.highlight.range, - i - ) ? context.highlight.opacity : 0.; + const auto highlighted = (highlight.empty() && !i) + || IsGroupItemSelection(highlight, i); + const auto highlightOpacity = highlighted + ? context.highlight.opacity + : 0.; if (textSelection) { selection = part.content->skipSelection(selection); } @@ -517,6 +547,7 @@ TextSelection GroupedMedia::adjustSelection( selection.to = modified.to; return selection; } + checked = till; } return selection; } @@ -564,6 +595,50 @@ TextForMimeData GroupedMedia::selectedText( return result; } +SelectedQuote GroupedMedia::selectedQuote(TextSelection selection) const { + if (_mode != Mode::Column) { + return _captionItem + ? Element::FindSelectedQuote(_caption, selection, _captionItem) + : SelectedQuote(); + } + for (const auto &part : _parts) { + const auto next = part.content->skipSelection(selection); + if (next.to - next.from != selection.to - selection.from) { + if (!next.empty()) { + return SelectedQuote(); + } + auto result = part.content->selectedQuote(selection); + result.item = part.item; + return result; + } + selection = next; + } + return {}; +} + +TextSelection GroupedMedia::selectionFromQuote( + not_null item, + const TextWithEntities "e) const { + if (_mode != Mode::Column) { + return (_captionItem == item) + ? Element::FindSelectionFromQuote(_caption, item, quote) + : TextSelection(); + } + const auto i = ranges::find(_parts, item, &Part::item); + if (i == end(_parts)) { + return {}; + } + const auto index = int(i - begin(_parts)); + auto result = i->content->selectionFromQuote(item, quote); + if (result.empty()) { + return AddGroupItemSelection({}, index); + } + for (auto j = i; j != begin(_parts);) { + result = (--j)->content->unskipSelection(result); + } + return result; +} + auto GroupedMedia::getBubbleSelectionIntervals( TextSelection selection) const -> std::vector { @@ -666,16 +741,15 @@ bool GroupedMedia::validateGroupParts( } void GroupedMedia::refreshCaption() { - using PartPtrOpt = std::optional; - const auto captionPart = [&]() -> PartPtrOpt { + const auto part = [&]() -> const Part* { if (_mode == Mode::Column) { - return std::nullopt; + return nullptr; } - auto result = PartPtrOpt(); + auto result = (const Part*)nullptr; for (const auto &part : _parts) { if (!part.item->emptyText()) { if (result) { - return std::nullopt; + return nullptr; } else { result = ∂ } @@ -683,8 +757,7 @@ void GroupedMedia::refreshCaption() { } return result; }(); - if (captionPart) { - const auto &part = (*captionPart); + if (part) { _caption = createCaption(part->item); _captionItem = part->item; } else { diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h index c66864063..b6fbc77d9 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h @@ -55,6 +55,10 @@ public: DocumentData *getDocument() const override; TextForMimeData selectedText(TextSelection selection) const override; + SelectedQuote selectedQuote(TextSelection selection) const override; + TextSelection selectionFromQuote( + not_null item, + const TextWithEntities "e) const override; std::vector getBubbleSelectionIntervals( TextSelection selection) const override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index b0afe1b64..de72e7786 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -1051,13 +1051,14 @@ TextForMimeData Photo::selectedText(TextSelection selection) const { return _caption.toTextForMimeData(selection); } -TextWithEntities Photo::selectedQuote(TextSelection selection) const { - return parent()->selectedQuote(_caption, selection); +SelectedQuote Photo::selectedQuote(TextSelection selection) const { + return Element::FindSelectedQuote(_caption, selection, _realParent); } TextSelection Photo::selectionFromQuote( + not_null item, const TextWithEntities "e) const { - return parent()->selectionFromQuote(_caption, quote); + return Element::FindSelectionFromQuote(_caption, item, quote); } void Photo::hideSpoilers() { diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.h b/Telegram/SourceFiles/history/view/media/history_view_photo.h index b76bbe264..7213dca21 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.h +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.h @@ -57,8 +57,9 @@ public: } TextForMimeData selectedText(TextSelection selection) const override; - TextWithEntities selectedQuote(TextSelection selection) const override; + SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( + not_null item, const TextWithEntities "e) const override; PhotoData *getPhoto() const override { From 10022a3c6dbd6899ece0e7ef32c21ad96a1f65b5 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 23:06:21 +0400 Subject: [PATCH 22/44] Highlight quotes in replies to file albums. --- .../SourceFiles/data/data_media_types.cpp | 5 +-- .../history/view/history_view_element.cpp | 9 +++-- .../view/media/history_view_document.cpp | 6 ++++ .../view/media/history_view_media_grouped.cpp | 34 +++++++++++-------- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index 9cf49244a..cb0278a27 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -538,6 +538,7 @@ ItemPreview Media::toGroupPreview( auto videoCount = 0; auto audioCount = 0; auto fileCount = 0; + auto manyCaptions = false; for (const auto &item : items) { if (const auto media = item->media()) { if (media->photo()) { @@ -571,12 +572,12 @@ ItemPreview Media::toGroupPreview( if (result.text.text.isEmpty()) { result.text = original; } else { - result.text = {}; + manyCaptions = true; } } } } - if (result.text.text.isEmpty()) { + if (manyCaptions || result.text.text.isEmpty()) { const auto mediaCount = photoCount + videoCount; auto genericText = (photoCount && videoCount) ? tr::lng_in_dlg_media_count(tr::now, lt_count, mediaCount) diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 68f8c49ad..991d158dc 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -621,6 +621,9 @@ void Element::paintHighlight( Painter &p, const PaintContext &context, int geometryHeight) const { + if (context.highlight.opacity == 0.) { + return; + } const auto top = marginTop(); const auto bottom = marginBottom(); const auto fill = qMin(top, bottom); @@ -636,12 +639,8 @@ void Element::paintCustomHighlight( int y, int height, not_null item) const { - const auto opacity = context.highlight.opacity; - if (opacity == 0.) { - return; - } const auto o = p.opacity(); - p.setOpacity(o * opacity); + p.setOpacity(o * context.highlight.opacity); p.fillRect(0, y, width(), height, context.st->msgSelectOverlay()); p.setOpacity(o); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 7530b31ff..06825b37d 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -1397,6 +1397,8 @@ void Document::drawGrouped( float64 highlightOpacity, not_null cacheKey, not_null cache) const { + const auto maybeMediaHighlight = context.highlightPathCache + && context.highlightPathCache->isEmpty(); p.translate(geometry.topLeft()); draw( p, @@ -1404,6 +1406,10 @@ void Document::drawGrouped( geometry.width(), LayoutMode::Grouped, rounding); + if (maybeMediaHighlight + && !context.highlightPathCache->isEmpty()) { + context.highlightPathCache->translate(geometry.topLeft()); + } p.translate(-geometry.topLeft()); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp index 9766c5aaa..402fb4d05 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp @@ -286,6 +286,9 @@ void GroupedMedia::drawHighlight( Painter &p, const PaintContext &context, int top) const { + if (context.highlight.opacity == 0.) { + return; + } auto selection = context.highlight.range; if (_mode != Mode::Column) { if (!selection.empty() && !IsSubGroupSelection(selection)) { @@ -305,9 +308,15 @@ void GroupedMedia::drawHighlight( const auto &part = _parts[i]; const auto rect = part.geometry.translated(0, skip); const auto full = (!i && empty) - || (subpart && IsGroupItemSelection(selection, i)); - auto copy = context; + || (subpart && IsGroupItemSelection(selection, i)) + || (!subpart + && !selection.empty() + && (selection.from < part.content->fullSelectionLength())); + if (!subpart) { + selection = part.content->skipSelection(selection); + } if (full) { + auto copy = context; copy.highlight.range = {}; _parent->paintCustomHighlight( p, @@ -315,18 +324,7 @@ void GroupedMedia::drawHighlight( rect.y(), rect.height(), part.item); - } else if (!selection.empty()) { - copy.highlight.range = selection; - selection = part.content->skipSelection(selection); - } else { - break; } - _parent->paintCustomHighlight( - p, - copy, - rect.y(), - rect.height(), - part.item); } } @@ -344,10 +342,10 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { const auto rounding = inWebPage ? Ui::BubbleRounding{ kSmall, kSmall, kSmall, kSmall } : adjustedBubbleRoundingWithCaption(_caption); - const auto highlight = context.highlight.range; + auto highlight = context.highlight.range; for (auto i = 0, count = int(_parts.size()); i != count; ++i) { const auto &part = _parts[i]; - const auto partContext = context.withSelection(fullSelection + auto partContext = context.withSelection(fullSelection ? FullSelection : textSelection ? selection @@ -359,9 +357,15 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { const auto highlightOpacity = highlighted ? context.highlight.opacity : 0.; + partContext.highlight.range = highlighted + ? TextSelection() + : highlight; if (textSelection) { selection = part.content->skipSelection(selection); } + if (!highlighted) { + highlight = part.content->skipSelection(highlight); + } if (!part.cache.isNull()) { wasCache = true; } From 097c3c4a5a55ffc282405a3e108230c914b0f836 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 23:25:26 +0400 Subject: [PATCH 23/44] Allow changing album quote before sending. --- .../controls/history_view_draft_options.cpp | 48 +++++++++++-------- .../history/view/history_view_element.h | 1 + .../view/media/history_view_media_grouped.cpp | 3 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp index 9a4b2ba53..307aa0224 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp @@ -99,9 +99,8 @@ public: not_null history); ~PreviewWrap(); - [[nodiscard]] rpl::producer showQuoteSelector( - not_null item, - const TextWithEntities "e); + [[nodiscard]] rpl::producer showQuoteSelector( + const SelectedQuote "e); [[nodiscard]] rpl::producer showLinkSelector( const TextWithTags &message, Data::WebPageDraft webpage, @@ -212,13 +211,13 @@ PreviewWrap::~PreviewWrap() { } } -rpl::producer PreviewWrap::showQuoteSelector( - not_null item, - const TextWithEntities "e) { +rpl::producer PreviewWrap::showQuoteSelector( + const SelectedQuote "e) { _selection.reset(TextSelection()); + const auto item = quote.item; const auto group = item->history()->owner().groups().find(item); - const auto leader = group ? group->items.front() : item; + const auto leader = group ? group->items.front().get() : item; _element = leader->createView(_delegate.get()); _link = _pressedLink = nullptr; @@ -235,10 +234,13 @@ rpl::producer PreviewWrap::showQuoteSelector( initElement(); - _selection = _element->selectionFromQuote(item, quote); + _selection = _element->selectionFromQuote(item, quote.text); return _selection.value( ) | rpl::map([=](TextSelection selection) { - return _element->selectedQuote(selection).text; + if (const auto result = _element->selectedQuote(selection)) { + return result; + } + return SelectedQuote{ item }; }); } @@ -586,7 +588,7 @@ void DraftOptionsBox( struct State { rpl::variable
shown; rpl::lifetime shownLifetime; - rpl::variable quote; + rpl::variable quote; Data::WebPageDraft webpage; WebPageData *preview = nullptr; QString link; @@ -598,7 +600,7 @@ void DraftOptionsBox( rpl::lifetime resolveLifetime; }; const auto state = box->lifetime().make_state(); - state->quote = draft.reply.quote; + state->quote = SelectedQuote{ replyItem, draft.reply.quote }; state->webpage = draft.webpage; state->preview = previewData; state->shown = previewData ? Section::Link : Section::Reply; @@ -636,8 +638,10 @@ void DraftOptionsBox( const auto &highlight = args.highlight; const auto &clearOldDraft = args.clearOldDraft; const auto resolveReply = [=] { + const auto current = state->quote.current(); auto result = draft.reply; - result.quote = state->quote.current(); + result.messageId = current.item->fullId(); + result.quote = current.text; return result; }; const auto finish = [=]( @@ -652,7 +656,8 @@ void DraftOptionsBox( const auto setupReplyActions = [=] { AddFilledSkip(bottom); - if (replyItem->allowsForward()) { + const auto item = state->quote.current().item; + if (item->allowsForward()) { Settings::AddButton( bottom, tr::lng_reply_in_another_chat(), @@ -679,7 +684,7 @@ void DraftOptionsBox( finish({}, state->webpage); }); - if (!replyItem->originalText().empty()) { + if (!item->originalText().empty()) { AddFilledSkip(bottom); Settings::AddDividerText( bottom, @@ -808,7 +813,6 @@ void DraftOptionsBox( state->shownLifetime.destroy(); if (shown == Section::Reply) { state->quote = state->wrap->showQuoteSelector( - replyItem, state->quote.current()); setupReplyActions(); } else { @@ -827,8 +831,8 @@ void DraftOptionsBox( auto save = rpl::combine( state->quote.value(), state->shown.value() - ) | rpl::map([=](const TextWithEntities "e, Section shown) { - return (quote.empty() || shown != Section::Reply) + ) | rpl::map([=](const SelectedQuote "e, Section shown) { + return (quote.text.empty() || shown != Section::Reply) ? tr::lng_settings_save() : tr::lng_reply_quote_selected(); }) | rpl::flatten_latest(); @@ -843,14 +847,20 @@ void DraftOptionsBox( if (replyItem) { args.show->session().data().itemRemoved( ) | rpl::filter([=](not_null removed) { - return removed == replyItem; + const auto current = state->quote.current().item; + if ((removed == replyItem) || (removed == current)) { + return true; + } + const auto group = current->history()->owner().groups().find( + current); + return (group && ranges::contains(group->items, removed)); }) | rpl::start_with_next([=] { if (previewData) { state->tabs = nullptr; box->setPinnedToTopContent( object_ptr(nullptr)); box->setNoContentMargin(false); - box->setTitle(state->quote.current().empty() + box->setTitle(state->quote.current().text.empty() ? tr::lng_reply_options_header() : tr::lng_reply_options_quote()); state->shown = Section::Link; diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 8261628d7..3cd78c711 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -273,6 +273,7 @@ struct SelectedQuote { explicit operator bool() const { return item && !text.empty(); } + friend inline bool operator==(SelectedQuote, SelectedQuote) = default; }; class Element diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp index 402fb4d05..bea617b23 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp @@ -343,6 +343,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { ? Ui::BubbleRounding{ kSmall, kSmall, kSmall, kSmall } : adjustedBubbleRoundingWithCaption(_caption); auto highlight = context.highlight.range; + const auto subpartHighlight = IsSubGroupSelection(highlight); for (auto i = 0, count = int(_parts.size()); i != count; ++i) { const auto &part = _parts[i]; auto partContext = context.withSelection(fullSelection @@ -363,7 +364,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { if (textSelection) { selection = part.content->skipSelection(selection); } - if (!highlighted) { + if (!subpartHighlight) { highlight = part.content->skipSelection(highlight); } if (!part.cache.isNull()) { From 35e457c9243791b8ddb53f452686b9b6f3a9c441 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 31 Oct 2023 23:41:41 +0400 Subject: [PATCH 24/44] Fix quote create in RepliesWidget. --- .../history/view/controls/history_view_compose_controls.cpp | 1 + .../SourceFiles/history/view/history_view_context_menu.cpp | 2 +- .../SourceFiles/history/view/history_view_list_widget.cpp | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) 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 43f505b6b..71e784f0b 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -1355,6 +1355,7 @@ void ComposeControls::init() { cancelReplyMessage(); } _preview->apply(webpage); + _field->setFocus(); }; const auto replyToId = reply.messageId; const auto highlight = crl::guard(_wrap.get(), [=] { diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index 9ae59286b..1775a3177 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -581,7 +581,7 @@ bool AddReplyToMessageAction( const ContextMenuRequest &request, not_null list) { const auto context = list->elementContext(); - const auto item = request.item; + const auto item = request.quoteItem ? request.quoteItem : request.item; const auto topic = item ? item->topic() : nullptr; const auto peer = item ? item->history()->peer.get() : nullptr; if (!item diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 28932369a..a1783dae2 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2604,8 +2604,9 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { request.view = _overElement; request.item = overItem; request.pointState = _overState.pointState; - const auto quote = (overItemView && _selectedTextItem == overItem) - ? overItemView->selectedQuote(_selectedTextRange) + const auto quote = (_overElement + && _selectedTextItem == _overElement->data()) + ? _overElement->selectedQuote(_selectedTextRange) : SelectedQuote(); request.quote = quote.text; request.quoteItem = quote.item; From 8e369a4aa5aa9c5ab4addce4c980d29119c5d559 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 08:44:25 +0400 Subject: [PATCH 25/44] Fix moved up link preview with long text. --- Telegram/SourceFiles/history/view/history_view_message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index a73b2e18c..e5f2bb640 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -4049,7 +4049,7 @@ void Message::refreshInfoSkipBlock() { return false; } else if (item->Has()) { return false; - } else if (media && media->isDisplayed()) { + } else if (media && media->isDisplayed() && !_invertMedia) { return false; } else if (_reactions) { return false; From 728ed02a1cf3400091b37a72659bdb046e793e85 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 09:17:08 +0400 Subject: [PATCH 26/44] Allow selecting text in webpage previews. --- .../history/history_inner_widget.cpp | 9 +++- .../history/view/history_view_element.cpp | 7 ++- .../history/view/history_view_element.h | 2 + .../history/view/history_view_message.cpp | 10 ++++ .../history/view/history_view_message.h | 2 + .../history/view/media/history_view_game.cpp | 51 ++++++++++++++++--- .../history/view/media/history_view_game.h | 17 ++++--- .../history/view/media/history_view_media.cpp | 5 ++ .../history/view/media/history_view_media.h | 2 + .../view/media/history_view_web_page.cpp | 5 ++ .../view/media/history_view_web_page.h | 2 + 11 files changed, 98 insertions(+), 14 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 552905840..eee1ff08d 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1673,7 +1673,10 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but Ui::MarkInactivePress(_controller->widget(), false); } - if (ClickHandler::getPressed()) { + const auto pressed = ClickHandler::getPressed(); + if (pressed + && (!Element::Hovered() + || !Element::Hovered()->allowTextSelectionByHandler(pressed))) { _mouseAction = MouseAction::PrepareDrag; } else if (inSelectionMode()) { if (_dragStateItem @@ -3837,6 +3840,10 @@ void HistoryInner::mouseActionUpdate() { selState = view->adjustSelection(selState, _mouseSelectType); } } + if (!selState.empty()) { + // We started selecting text in web page preview. + ClickHandler::unpressed(); + } if (_selected[_mouseActionItem] != selState) { _selected[_mouseActionItem] = selState; repaintItem(_mouseActionItem); diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 991d158dc..eeec9d86b 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -1424,7 +1424,12 @@ HistoryMessageReply *Element::displayedReply() const { } bool Element::toggleSelectionByHandlerClick( - const ClickHandlerPtr &handler) const { + const ClickHandlerPtr &handler) const { + return false; +} + +bool Element::allowTextSelectionByHandler( + const ClickHandlerPtr &handler) const { return false; } diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 3cd78c711..db3933b98 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -462,6 +462,8 @@ public: } [[nodiscard]] virtual bool toggleSelectionByHandlerClick( const ClickHandlerPtr &handler) const; + [[nodiscard]] virtual bool allowTextSelectionByHandler( + const ClickHandlerPtr &handler) const; struct VerticalRepaintRange { int top = 0; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index e5f2bb640..f5a6d655d 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -3148,6 +3148,16 @@ bool Message::toggleSelectionByHandlerClick( return false; } +bool Message::allowTextSelectionByHandler( + const ClickHandlerPtr &handler) const { + if (const auto media = this->media()) { + if (media->allowTextSelectionByHandler(handler)) { + return true; + } + } + return false; +} + bool Message::hasFromName() const { switch (context()) { case Context::AdminLog: diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h index aa66b0cf5..aeba7c1aa 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.h +++ b/Telegram/SourceFiles/history/view/history_view_message.h @@ -140,6 +140,8 @@ public: [[nodiscard]] HistoryMessageReply *displayedReply() const override; [[nodiscard]] bool toggleSelectionByHandlerClick( const ClickHandlerPtr &handler) const override; + [[nodiscard]] bool allowTextSelectionByHandler( + const ClickHandlerPtr &handler) const override; [[nodiscard]] int infoWidth() const override; [[nodiscard]] int bottomInfoFirstLineWidth() const override; [[nodiscard]] bool bottomInfoIsWide() const override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_game.cpp b/Telegram/SourceFiles/history/view/media/history_view_game.cpp index a91f8350d..24ba5187c 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_game.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_game.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/text_utilities.h" #include "ui/cached_round_corners.h" #include "ui/chat/chat_style.h" +#include "ui/effects/ripple_animation.h" #include "ui/painter.h" #include "ui/power_saving.h" #include "core/ui_integration.h" @@ -226,6 +227,13 @@ void Game::draw(Painter &p, const PaintContext &context) const { Ui::Text::ValidateQuotePaintCache(*cache, _st); Ui::Text::FillQuotePaint(p, outer, *cache, _st); + if (_ripple) { + _ripple->paint(p, outer.x(), outer.y(), width(), &cache->bg); + if (_ripple->empty()) { + _ripple = nullptr; + } + } + auto lineHeight = UnitedLineHeight(); if (_titleLines) { p.setPen(cache->icon); @@ -322,7 +330,6 @@ TextState Game::textState(QPoint point, StateRequest request) const { auto tshift = inner.top(); auto paintw = inner.width(); - auto inThumb = false; auto symbolAdd = 0; auto lineHeight = UnitedLineHeight(); if (_titleLines) { @@ -353,11 +360,7 @@ TextState Game::textState(QPoint point, StateRequest request) const { } tshift += _descriptionLines * lineHeight; } - if (inThumb) { - if (_parent->data()->isHistoryEntry()) { - result.link = _openl; - } - } else if (_attach) { + if (_attach) { auto attachAtTop = !_titleLines && !_descriptionLines; if (!attachAtTop) tshift += st::mediaInBubbleSkip; @@ -375,6 +378,12 @@ TextState Game::textState(QPoint point, StateRequest request) const { } } } + if (_parent->data()->isHistoryEntry()) { + if (!result.link && outer.contains(point)) { + result.link = _openl; + } + } + _lastPoint = point - outer.topLeft(); result.symbol += symbolAdd; return result; @@ -399,11 +408,41 @@ void Game::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { } void Game::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { + if (p == _openl) { + if (pressed) { + if (!_ripple) { + const auto full = QRect(0, 0, width(), height()); + const auto outer = full.marginsRemoved(inBubblePadding()); + const auto owner = &parent()->history()->owner(); + _ripple = std::make_unique( + st::defaultRippleAnimation, + Ui::RippleAnimation::RoundRectMask( + outer.size(), + _st.radius), + [=] { owner->requestViewRepaint(parent()); }); + } + _ripple->add(_lastPoint); + } else if (_ripple) { + _ripple->lastStop(); + } + } if (_attach) { _attach->clickHandlerPressedChanged(p, pressed); } } +bool Game::toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const { + return _attach && _attach->toggleSelectionByHandlerClick(p); +} + +bool Game::allowTextSelectionByHandler(const ClickHandlerPtr &p) const { + return (p == _openl); +} + +bool Game::dragItemByHandler(const ClickHandlerPtr &p) const { + return _attach && _attach->dragItemByHandler(p); +} + TextForMimeData Game::selectedText(TextSelection selection) const { auto titleResult = _title.toTextForMimeData(selection); auto descriptionResult = _description.toTextForMimeData( diff --git a/Telegram/SourceFiles/history/view/media/history_view_game.h b/Telegram/SourceFiles/history/view/media/history_view_game.h index 9cec01fdc..b7618bf69 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_game.h +++ b/Telegram/SourceFiles/history/view/media/history_view_game.h @@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class ReplyMarkupClickHandler; +namespace Ui { +class RippleAnimation; +} // namespace Ui + namespace HistoryView { class Game : public Media { @@ -35,12 +39,11 @@ public: return false; // we do not add _title and _description in FullSelection text copy. } - bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { - return _attach && _attach->toggleSelectionByHandlerClick(p); - } - bool dragItemByHandler(const ClickHandlerPtr &p) const override { - return _attach && _attach->dragItemByHandler(p); - } + bool toggleSelectionByHandlerClick( + const ClickHandlerPtr &p) const override; + bool allowTextSelectionByHandler( + const ClickHandlerPtr &p) const override; + bool dragItemByHandler(const ClickHandlerPtr &p) const override; TextForMimeData selectedText(TextSelection selection) const override; @@ -102,7 +105,9 @@ private: const not_null _data; std::shared_ptr _openl; std::unique_ptr _attach; + mutable std::unique_ptr _ripple; + mutable QPoint _lastPoint; int _gameTagWidth = 0; int _descriptionLines = 0; int _titleLines = 0; diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.cpp b/Telegram/SourceFiles/history/view/media/history_view_media.cpp index 69cad0ec4..8f9923c36 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media.cpp @@ -181,6 +181,11 @@ Storage::SharedMediaTypesMask Media::sharedMediaTypes() const { return {}; } +bool Media::allowTextSelectionByHandler( + const ClickHandlerPtr &handler) const { + return false; +} + not_null Media::parent() const { return _parent; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.h b/Telegram/SourceFiles/history/view/media/history_view_media.h index 392806575..7dadb5f87 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media.h @@ -136,6 +136,8 @@ public: // toggle selection instead of activating the pressed link [[nodiscard]] virtual bool toggleSelectionByHandlerClick( const ClickHandlerPtr &p) const = 0; + [[nodiscard]] virtual bool allowTextSelectionByHandler( + const ClickHandlerPtr &p) const; [[nodiscard]] virtual TextSelection adjustSelection( TextSelection selection, diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp index 844963a5e..a6bb07528 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp @@ -904,6 +904,11 @@ bool WebPage::toggleSelectionByHandlerClick( return _attach && _attach->toggleSelectionByHandlerClick(p); } +bool WebPage::allowTextSelectionByHandler( + const ClickHandlerPtr &p) const { + return (p == _openl); +} + bool WebPage::dragItemByHandler(const ClickHandlerPtr &p) const { return _attach && _attach->dragItemByHandler(p); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.h b/Telegram/SourceFiles/history/view/media/history_view_web_page.h index 0946714ff..bf9254e65 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.h +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.h @@ -50,6 +50,8 @@ public: bool toggleSelectionByHandlerClick( const ClickHandlerPtr &p) const override; + bool allowTextSelectionByHandler( + const ClickHandlerPtr &p) const override; bool dragItemByHandler(const ClickHandlerPtr &p) const override; TextForMimeData selectedText(TextSelection selection) const override; From af5ad84e72565ba2567e7b396a3ed4c5f2b656ab Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 09:26:40 +0400 Subject: [PATCH 27/44] Fix crashpad_handler linking workaround. Fixes #26873. --- Telegram/build/prepare/prepare.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/build/prepare/prepare.py b/Telegram/build/prepare/prepare.py index d1c11bd1d..c39d9b3c3 100644 --- a/Telegram/build/prepare/prepare.py +++ b/Telegram/build/prepare/prepare.py @@ -1211,7 +1211,7 @@ stage('crashpad', """ mac: git clone https://github.com/desktop-app/crashpad.git cd crashpad - git checkout 171b601938 + git checkout f07f49e287 git submodule init git submodule update third_party/mini_chromium ZLIB_PATH=$USED_PREFIX/include From caa1ae44367e65c8db7dde3607fa23af1259a454 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 16:39:36 +0400 Subject: [PATCH 28/44] Fix inline bots with secondary usernames. --- Telegram/SourceFiles/chat_helpers/message_field.cpp | 5 +---- Telegram/SourceFiles/history/history_widget.cpp | 6 ++---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 9c5b37751..475e87cb3 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -493,10 +493,7 @@ InlineBotQuery ParseInlineBotQuery( result.lookingUpBot = true; } } - if (result.lookingUpBot) { - result.query = QString(); - return result; - } else if (result.bot + if (result.bot && (!result.bot->isBot() || result.bot->botInfo->inlinePlaceholder.isEmpty())) { result.bot = nullptr; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index de130e3c1..0935f0865 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1393,9 +1393,7 @@ void HistoryWidget::updateInlineBotQuery() { _inlineBotResolveRequestId = _api.request(MTPcontacts_ResolveUsername( MTP_string(username) )).done([=](const MTPcontacts_ResolvedPeer &result) { - Expects(result.type() == mtpc_contacts_resolvedPeer); - - const auto &data = result.c_contacts_resolvedPeer(); + const auto &data = result.data(); const auto resolvedBot = [&]() -> UserData* { if (const auto user = session().data().processUsers( data.vusers())) { @@ -5198,7 +5196,7 @@ void HistoryWidget::updateFieldPlaceholder() { if (!_editMsgId && _inlineBot && !_inlineLookingUpBot) { _field->setPlaceholder( rpl::single(_inlineBot->botInfo->inlinePlaceholder.mid(1)), - _inlineBot->username().size() + 2); + _inlineBotUsername.size() + 2); return; } From 5966c74a270a3b48e34543025d8f50c67666f3e1 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 1 Nov 2023 16:55:18 +0300 Subject: [PATCH 29/44] Added ability to go to message from message preview in statistics info. --- Telegram/SourceFiles/boxes/peer_list_box.cpp | 2 +- .../info_statistics_inner_widget.cpp | 42 ++++++++++++++++++- .../settings/settings_advanced.cpp | 2 +- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index 2c1e361fb..3395a5850 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -760,7 +760,7 @@ int PeerListRow::paintNameIconGetWidth( nameWidth, outerWidth, { - .peer = _peer, + .peer = peer(), .verified = &(selected ? st::dialogsVerifiedIconOver : st::dialogsVerifiedIcon), diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp index c90ee395c..baa569ab3 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_statistics.h" #include "apiwrap.h" +#include "base/event_filter.h" #include "data/data_peer.h" #include "data/data_session.h" #include "history/history_item.h" @@ -28,9 +29,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/rect.h" #include "ui/toast/toast.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/popup_menu.h" #include "ui/widgets/scroll_area.h" #include "ui/wrap/slide_wrap.h" #include "styles/style_boxes.h" +#include "styles/style_menu_icons.h" #include "styles/style_settings.h" #include "styles/style_statistics.h" @@ -43,6 +46,39 @@ struct Descriptor final { not_null toastParent; }; +void AddContextMenu( + not_null button, + not_null controller, + not_null item) { + const auto fullId = item->fullId(); + const auto contextMenu = button->lifetime() + .make_state>(); + const auto showMenu = [=] { + *contextMenu = base::make_unique_q( + button, + st::popupMenuWithIcons); + const auto go = [=] { + const auto &session = controller->parentController(); + if (const auto item = session->session().data().message(fullId)) { + session->showMessage(item); + } + }; + contextMenu->get()->addAction( + tr::lng_context_to_msg(tr::now), + crl::guard(controller, go), + &st::menuIconShowInChat); + contextMenu->get()->popup(QCursor::pos()); + }; + + base::install_event_filter(button, [=](not_null e) { + if (e->type() == QEvent::ContextMenu) { + showMenu(); + return base::EventFilterResult::Cancel; + } + return base::EventFilterResult::Continue; + }); +} + void ProcessZoom( const Descriptor &d, not_null widget, @@ -544,7 +580,9 @@ void InnerWidget::fill() { if (_state.stats.message) { if (const auto i = _peer->owner().message(_contextId)) { ::Settings::AddSkip(inner); - inner->add(object_ptr(this, i, -1, -1, QImage())); + const auto preview = inner->add( + object_ptr(this, i, -1, -1, QImage())); + AddContextMenu(preview, _controller, i); ::Settings::AddSkip(inner); ::Settings::AddDivider(inner); } @@ -639,6 +677,8 @@ void InnerWidget::fillRecentPosts() { info.forwardsCount, std::move(cachedPreview)); + AddContextMenu(button, _controller, item); + _messagePreviews.push_back(raw); raw->show(); button->sizeValue( diff --git a/Telegram/SourceFiles/settings/settings_advanced.cpp b/Telegram/SourceFiles/settings/settings_advanced.cpp index 1c10841d0..3d92fb323 100644 --- a/Telegram/SourceFiles/settings/settings_advanced.cpp +++ b/Telegram/SourceFiles/settings/settings_advanced.cpp @@ -549,7 +549,7 @@ void SetupSystemIntegrationContent( }, warnBeforeQuit->lifetime()); #ifndef OS_MAC_STORE - const auto enabled = [] { + const auto enabled = [=] { const auto digest = base::Platform::CurrentCustomAppIconDigest(); return digest && (settings->macRoundIconDigest() == digest); }; From 597195a2e25d459aee8637c54fc15d143d836714 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 1 Nov 2023 15:47:25 +0300 Subject: [PATCH 30/44] Replaced Session Controller with Navigation for resolving of giftcodes. --- .../SourceFiles/boxes/gift_premium_box.cpp | 20 +++++++++---------- Telegram/SourceFiles/boxes/gift_premium_box.h | 7 ++++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index c7b59f44b..84ea6a429 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -281,7 +281,7 @@ struct GiftCodeLink { [[nodiscard]] object_ptr MakePeerTableValue( not_null parent, - not_null controller, + not_null controller, PeerId id) { auto result = object_ptr(parent); const auto raw = result.data(); @@ -309,7 +309,7 @@ struct GiftCodeLink { label->setTextColorOverride(st::windowActiveTextFg->c); raw->setClickedCallback([=] { - controller->show(PrepareShortInfoBox(peer, controller)); + controller->uiShow()->showBox(PrepareShortInfoBox(peer, controller)); }); return result; @@ -350,7 +350,7 @@ not_null AddTableRow( void AddTableRow( not_null table, rpl::producer label, - not_null controller, + not_null controller, PeerId id) { if (!id) { return; @@ -416,7 +416,7 @@ QString GiftDuration(int months) { void GiftCodeBox( not_null box, - not_null controller, + not_null controller, const QString &slug) { struct State { rpl::variable data; @@ -552,7 +552,7 @@ void GiftCodeBox( st::giveawayGiftCodeFooterMargin); footer->setClickHandlerFilter([=](const auto &...) { const auto chosen = [=](not_null thread) { - const auto content = controller->content(); + const auto content = controller->parentController()->content(); return content->shareUrl( thread, MakeGiftCodeLink(&controller->session(), slug).link, @@ -608,13 +608,13 @@ void GiftCodeBox( } void ResolveGiftCode( - not_null controller, + not_null controller, const QString &slug) { const auto done = [=](Api::GiftCode code) { if (!code) { controller->showToast(tr::lng_gift_link_expired(tr::now)); } else { - controller->show(Box(GiftCodeBox, controller, slug)); + controller->uiShow()->showBox(Box(GiftCodeBox, controller, slug)); } }; controller->session().api().premium().checkGiftCode( @@ -624,7 +624,7 @@ void ResolveGiftCode( void GiveawayInfoBox( not_null box, - not_null controller, + not_null controller, Data::Giveaway giveaway, Api::GiveawayInfo info) { using State = Api::GiveawayState; @@ -784,7 +784,7 @@ void GiveawayInfoBox( } void ResolveGiveawayInfo( - not_null controller, + not_null controller, not_null peer, MsgId messageId, Data::Giveaway giveaway) { @@ -793,7 +793,7 @@ void ResolveGiveawayInfo( controller->showToast( tr::lng_confirm_phone_link_invalid(tr::now)); } else { - controller->show( + controller->uiShow()->showBox( Box(GiveawayInfoBox, controller, giveaway, info)); } }; diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.h b/Telegram/SourceFiles/boxes/gift_premium_box.h index 3f6d273bc..a1062dead 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.h +++ b/Telegram/SourceFiles/boxes/gift_premium_box.h @@ -25,6 +25,7 @@ class GenericBox; namespace Window { class SessionController; +class SessionNavigation; } // namespace Window class GiftPremiumValidator final { @@ -47,14 +48,14 @@ private: void GiftCodeBox( not_null box, - not_null controller, + not_null controller, const QString &slug); void ResolveGiftCode( - not_null controller, + not_null controller, const QString &slug); void ResolveGiveawayInfo( - not_null controller, + not_null controller, not_null peer, MsgId messageId, Data::Giveaway giveaway); From 4955cdcdceab204e684bf6d8226060743f355102 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 21:02:54 +0400 Subject: [PATCH 31/44] Wait for main menu bot icon to load. --- .../inline_bots/bot_attach_web_view.h | 3 +++ .../SourceFiles/window/window_main_menu.cpp | 20 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h index ce8a167e4..a389c9627 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h @@ -134,6 +134,9 @@ public: [[nodiscard]] rpl::producer<> attachBotsUpdates() const { return _attachBotsUpdates.events(); } + void notifyBotIconLoaded() { + _attachBotsUpdates.fire({}); + } [[nodiscard]] bool disclaimerAccepted( const AttachWebViewBot &bot) const; [[nodiscard]] bool showMainMenuNewBadge( diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index 046e7119d..3dde58473 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -59,6 +59,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_domain.h" #include "mtproto/mtp_instance.h" #include "mtproto/mtproto_config.h" +#include "data/data_document_media.h" #include "data/data_folder.h" #include "data/data_session.h" #include "data/data_user.h" @@ -205,6 +206,9 @@ void SetupMenuBots( const auto wrap = container->add( object_ptr(container)); const auto bots = &controller->session().attachWebView(); + const auto iconLoadLifetime = wrap->lifetime().make_state< + rpl::lifetime + >(); rpl::single( rpl::empty @@ -214,7 +218,20 @@ void SetupMenuBots( const auto width = container->widthNoMargins(); wrap->clear(); for (const auto &bot : bots->attachBots()) { - if (!bot.inMainMenu) { + const auto user = bot.user; + if (!bot.inMainMenu || !bot.media) { + continue; + } else if (const auto media = bot.media; !media->loaded()) { + if (!*iconLoadLifetime) { + auto &session = user->session(); + *iconLoadLifetime = session.downloaderTaskFinished( + ) | rpl::start_with_next([=] { + if (media->loaded()) { + iconLoadLifetime->destroy(); + bots->notifyBotIconLoaded(); + } + }); + } continue; } const auto button = Settings::AddButton( @@ -233,7 +250,6 @@ void SetupMenuBots( st::mainMenuButton.iconLeft, (height - icon->height()) / 2); }, button->lifetime()); - const auto user = bot.user; const auto weak = Ui::MakeWeak(container); button->setAcceptBoth(true); button->clicks( From 3da44eb5dd01948c8cad10c682c2f38287a53b8c Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 21:04:04 +0400 Subject: [PATCH 32/44] Fix attach menu suggested bot launch. --- .../SourceFiles/inline_bots/bot_attach_web_view.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp index 29842290b..2a0a539db 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp @@ -828,6 +828,19 @@ void AttachWebView::requestWithOptionalConfirm( void AttachWebView::request(const WebViewButton &button) { Expects(_context != nullptr && _bot != nullptr); + if (button.fromAttachMenu) { + const auto bot = ranges::find( + _attachBots, + not_null{ _bot }, + &AttachWebViewBot::user); + if (bot == end(_attachBots) || bot->inactive) { + requestAddToMenu(_bot, AddToMenuOpenAttach{ + .startCommand = button.startCommand, + }); + return; + } + } + _startCommand = button.startCommand; const auto &action = _context->action; From 7d5d086ade3eb7d1fce91f9cbac7bda00a63472c Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 21:04:23 +0400 Subject: [PATCH 33/44] Allow messages when accepting miniapp terms. --- .../inline_bots/bot_attach_web_view.cpp | 67 +++++++++---------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp index 2a0a539db..3c045f29c 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp @@ -1537,8 +1537,10 @@ void AttachWebView::confirmAddToMenu( } _confirmAddBox = active->show(Box([=](not_null box) { const auto allowed = std::make_shared(); + const auto disclaimer = !disclaimerAccepted(bot); const auto done = [=](Fn close) { - const auto state = ((*allowed) && (*allowed)->checked()) + const auto state = (disclaimer + || (*allowed) && (*allowed)->checked()) ? ToggledState::AllowedToWrite : ToggledState::Added; toggleInMenu(bot.user, state, [=] { @@ -1551,13 +1553,22 @@ void AttachWebView::confirmAddToMenu( }); close(); }; - const auto disclaimer = !disclaimerAccepted(bot); if (disclaimer) { FillDisclaimerBox(box, [=] { _disclaimerAccepted.emplace(bot.user); _attachBotsUpdates.fire({}); done([] {}); }); + box->addRow(object_ptr( + box, + st::boxRowPadding.left())); + box->addRow(object_ptr( + box, + tr::lng_bot_will_be_added( + lt_bot, + rpl::single(Ui::Text::Bold(bot.name)), + Ui::Text::WithEntities), + st::boxLabel)); } else { Ui::ConfirmBox(box, { (bot.inMainMenu @@ -1569,40 +1580,26 @@ void AttachWebView::confirmAddToMenu( Ui::Text::WithEntities), done, }); - } - if (bot.requestWriteAccess) { - (*allowed) = box->addRow( - object_ptr( - box, - tr::lng_url_auth_allow_messages( - tr::now, - lt_bot, - Ui::Text::Bold(bot.name), - Ui::Text::WithEntities), - true, - st::urlAuthCheckbox), - style::margins( - st::boxRowPadding.left(), - (disclaimer - ? st::boxPhotoCaptionSkip - : st::boxRowPadding.left()), - st::boxRowPadding.right(), - st::boxRowPadding.left())); - (*allowed)->setAllowTextLines(); - } - if (disclaimer) { - if (!bot.requestWriteAccess) { - box->addRow(object_ptr( - box, - st::boxRowPadding.left())); + if (bot.requestWriteAccess) { + (*allowed) = box->addRow( + object_ptr( + box, + tr::lng_url_auth_allow_messages( + tr::now, + lt_bot, + Ui::Text::Bold(bot.name), + Ui::Text::WithEntities), + true, + st::urlAuthCheckbox), + style::margins( + st::boxRowPadding.left(), + (disclaimer + ? st::boxPhotoCaptionSkip + : st::boxRowPadding.left()), + st::boxRowPadding.right(), + st::boxRowPadding.left())); + (*allowed)->setAllowTextLines(); } - box->addRow(object_ptr( - box, - tr::lng_bot_will_be_added( - lt_bot, - rpl::single(Ui::Text::Bold(bot.name)), - Ui::Text::WithEntities), - st::boxLabel)); } })); } From cc97093c5aba61f469f7f9a23fc2ce09ab74e8d9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 22:13:21 +0400 Subject: [PATCH 34/44] Instantly jump-to-message on reply bar ctrl+click. --- .../SourceFiles/history/history_widget.cpp | 17 ++++++---- Telegram/SourceFiles/history/history_widget.h | 1 + .../history_view_compose_controls.cpp | 31 +++++++++---------- .../controls/history_view_compose_controls.h | 4 +-- .../controls/history_view_draft_options.cpp | 4 ++- .../controls/history_view_draft_options.h | 2 +- .../view/history_view_replies_section.cpp | 8 +++-- .../view/history_view_scheduled_section.cpp | 12 +++++-- 8 files changed, 47 insertions(+), 32 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 0935f0865..60c32aded 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6279,6 +6279,8 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) { } else { _forwardPanel->editOptions(controller()->uiShow()); } + } else if (_replyTo && (e->modifiers() & Qt::ControlModifier)) { + jumpToReply(_replyTo); } else if (_replyTo) { editDraftOptions(); } else if (_kbReplyTo) { @@ -6307,12 +6309,9 @@ void HistoryWidget::editDraftOptions() { _preview->apply(webpage); }; const auto replyToId = reply.messageId; - const auto highlight = [=] { - controller()->showPeerHistory( - replyToId.peer, - Window::SectionShow::Way::Forward, - replyToId.msg); - }; + const auto highlight = crl::guard(this, [=](FullReplyTo to) { + jumpToReply(to); + }); using namespace HistoryView::Controls; EditDraftOptions({ @@ -6328,6 +6327,12 @@ void HistoryWidget::editDraftOptions() { }); } +void HistoryWidget::jumpToReply(FullReplyTo to) { + if (const auto item = session().data().message(to.messageId)) { + JumpToMessageClickHandler(item, {}, to.quote)->onClick({}); + } +} + void HistoryWidget::keyPressEvent(QKeyEvent *e) { if (!_history) return; diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 4bf971ff2..87b7edde9 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -550,6 +550,7 @@ private: void setupPreview(); void editDraftOptions(); + void jumpToReply(FullReplyTo to); void messagesReceived(not_null peer, const MTPmessages_Messages &messages, int requestId); void messagesFailed(const MTP::Error &error, int requestId); 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 71e784f0b..d2da74625 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -130,7 +130,7 @@ public: [[nodiscard]] FullReplyTo replyingToMessage() const; [[nodiscard]] FullMsgId editMsgId() const; [[nodiscard]] rpl::producer editMsgIdValue() const; - [[nodiscard]] rpl::producer scrollToItemRequests() const; + [[nodiscard]] rpl::producer jumpToItemRequests() const; [[nodiscard]] rpl::producer<> editPhotoRequests() const; [[nodiscard]] rpl::producer<> editOptionsRequests() const; [[nodiscard]] MessageToEdit queryToEdit(); @@ -206,7 +206,7 @@ private: QRect _shownMessagePreviewRect; rpl::event_stream _visibleChanged; - rpl::event_stream _scrollToItemRequests; + rpl::event_stream _jumpToItemRequests; rpl::event_stream<> _editOptionsRequests; rpl::event_stream<> _editPhotoRequests; @@ -372,9 +372,14 @@ void FieldHeader::init() { if (_preview.parsed) { _editOptionsRequests.fire({}); } else if (isEditingMessage()) { - _scrollToItemRequests.fire(_editMsgId.current()); + _jumpToItemRequests.fire(FullReplyTo{ + .messageId = _editMsgId.current() + }); } else if (readyToForward()) { _forwardPanel->editOptions(_show); + } else if (reply + && (e->modifiers() & Qt::ControlModifier)) { + _jumpToItemRequests.fire_copy(reply); } else if (reply) { _editOptionsRequests.fire({}); } @@ -729,8 +734,8 @@ rpl::producer FieldHeader::editMsgIdValue() const { return _editMsgId.value(); } -rpl::producer FieldHeader::scrollToItemRequests() const { - return _scrollToItemRequests.events(); +rpl::producer FieldHeader::jumpToItemRequests() const { + return _jumpToItemRequests.events(); } rpl::producer<> FieldHeader::editPhotoRequests() const { @@ -1358,8 +1363,8 @@ void ComposeControls::init() { _field->setFocus(); }; const auto replyToId = reply.messageId; - const auto highlight = crl::guard(_wrap.get(), [=] { - _scrollToItemRequests.fire_copy(replyToId); + const auto highlight = crl::guard(_wrap.get(), [=](FullReplyTo to) { + _jumpToItemRequests.fire_copy(to); }); using namespace HistoryView::Controls; @@ -2888,16 +2893,10 @@ Data::WebPageDraft ComposeControls::webPageDraft() const { return _preview ? _preview->draft() : Data::WebPageDraft(); } -rpl::producer ComposeControls::scrollRequests() const { +rpl::producer ComposeControls::jumpToItemRequests() const { return rpl::merge( - _header->scrollToItemRequests(), - _scrollToItemRequests.events() - ) | rpl::map([=](FullMsgId id) -> Data::MessagePosition { - if (const auto item = session().data().message(id)) { - return item->position(); - } - return {}; - }); + _header->jumpToItemRequests(), + _jumpToItemRequests.events()); } bool ComposeControls::isEditingMessage() const { 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 be07fd1b5..9ae515d6c 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -159,7 +159,7 @@ public: [[nodiscard]] rpl::producer> attachRequests() const; [[nodiscard]] rpl::producer fileChosen() const; [[nodiscard]] rpl::producer photoChosen() const; - [[nodiscard]] rpl::producer scrollRequests() const; + [[nodiscard]] rpl::producer jumpToItemRequests() const; [[nodiscard]] rpl::producer inlineResultChosen() const; [[nodiscard]] rpl::producer sendActionUpdates() const; [[nodiscard]] rpl::producer> viewportEvents() const; @@ -358,7 +358,7 @@ private: const std::unique_ptr _wrap; const std::unique_ptr _writeRestricted; - rpl::event_stream _scrollToItemRequests; + rpl::event_stream _jumpToItemRequests; std::optional _backgroundRect; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp index 307aa0224..3438ab15d 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp @@ -673,7 +673,9 @@ void DraftOptionsBox( tr::lng_reply_show_in_chat(), st::settingsButton, { &st::menuIconShowInChat } - )->setClickedCallback(highlight); + )->setClickedCallback([=] { + highlight(resolveReply()); + }); Settings::AddButton( bottom, diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.h b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.h index 798e1fa0c..abe19b39e 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.h @@ -32,7 +32,7 @@ struct EditDraftOptionsArgs { std::vector links; std::shared_ptr resolver; Fn done; - Fn highlight; + Fn highlight; Fn clearOldDraft; }; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 8789099ea..c652ab2e8 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -791,9 +791,11 @@ void RepliesWidget::setupComposeControls() { sendInlineResult(chosen.result, chosen.bot, chosen.options, localId); }, lifetime()); - _composeControls->scrollRequests( - ) | rpl::start_with_next([=](Data::MessagePosition pos) { - showAtPosition(pos); + _composeControls->jumpToItemRequests( + ) | rpl::start_with_next([=](FullReplyTo to) { + if (const auto item = session().data().message(to.messageId)) { + JumpToMessageClickHandler(item, {}, to.quote)->onClick({}); + } }, lifetime()); _composeControls->scrollKeyEvents( diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 81fe77299..3f9314c40 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -274,9 +274,15 @@ void ScheduledWidget::setupComposeControls() { sendInlineResult(chosen.result, chosen.bot); }, lifetime()); - _composeControls->scrollRequests( - ) | rpl::start_with_next([=](Data::MessagePosition pos) { - showAtPosition(pos); + _composeControls->jumpToItemRequests( + ) | rpl::start_with_next([=](FullReplyTo to) { + if (const auto item = session().data().message(to.messageId)) { + if (item->isScheduled() && item->history() == _history) { + showAtPosition(item->position()); + } else { + JumpToMessageClickHandler(item, {}, to.quote)->onClick({}); + } + } }, lifetime()); _composeControls->scrollKeyEvents( From 42f96f3c4384945e2eb911983047bf1b5171ab65 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 22:23:38 +0400 Subject: [PATCH 35/44] Fix build with Xcode. --- Telegram/SourceFiles/history/history_view_highlight_manager.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Telegram/SourceFiles/history/history_view_highlight_manager.h b/Telegram/SourceFiles/history/history_view_highlight_manager.h index 7d74ed9a5..7fdcdfc0b 100644 --- a/Telegram/SourceFiles/history/history_view_highlight_manager.h +++ b/Telegram/SourceFiles/history/history_view_highlight_manager.h @@ -68,7 +68,6 @@ private: explicit operator bool() const { return itemId.operator bool(); } - friend inline auto operator<=>(Highlight, Highlight) = default; friend inline bool operator==(Highlight, Highlight) = default; }; From a8b959826c669f88d57b05d36fac8a94e4aeb68c Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 22:23:41 +0400 Subject: [PATCH 36/44] Don't activate main window in case of visible call window. Fixes #27017. --- Telegram/SourceFiles/calls/calls_instance.cpp | 21 ++++++++++++++----- Telegram/SourceFiles/calls/calls_instance.h | 4 +++- Telegram/SourceFiles/calls/calls_panel.cpp | 9 +++++--- Telegram/SourceFiles/calls/calls_panel.h | 1 + .../calls/group/calls_group_panel.cpp | 9 +++++--- .../calls/group/calls_group_panel.h | 1 + .../platform/mac/specific_mac_p.mm | 7 ++++++- 7 files changed, 39 insertions(+), 13 deletions(-) diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index d205ab4b0..d26140916 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -712,13 +712,24 @@ void Instance::destroyCurrentCall() { } } -bool Instance::hasActivePanel(not_null session) const { +bool Instance::hasVisiblePanel(Main::Session *session) const { if (inCall()) { - return (&_currentCall->user()->session() == session) - && _currentCallPanel->isActive(); + return _currentCallPanel->isVisible() + && (!session || (&_currentCall->user()->session() == session)); } else if (inGroupCall()) { - return (&_currentGroupCall->peer()->session() == session) - && _currentGroupCallPanel->isActive(); + return _currentGroupCallPanel->isVisible() + && (!session || (&_currentGroupCall->peer()->session() == session)); + } + return false; +} + +bool Instance::hasActivePanel(Main::Session *session) const { + if (inCall()) { + return _currentCallPanel->isActive() + && (!session || (&_currentCall->user()->session() == session)); + } else if (inGroupCall()) { + return _currentGroupCallPanel->isActive() + && (!session || (&_currentGroupCall->peer()->session() == session)); } return false; } diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h index 4113a600e..e15d800be 100644 --- a/Telegram/SourceFiles/calls/calls_instance.h +++ b/Telegram/SourceFiles/calls/calls_instance.h @@ -89,8 +89,10 @@ public: [[nodiscard]] rpl::producer currentGroupCallValue() const; [[nodiscard]] bool inCall() const; [[nodiscard]] bool inGroupCall() const; + [[nodiscard]] bool hasVisiblePanel( + Main::Session *session = nullptr) const; [[nodiscard]] bool hasActivePanel( - not_null session) const; + Main::Session *session = nullptr) const; bool activateCurrentCall(const QString &joinHash = QString()); bool minimizeCurrentActiveCall(); bool toggleFullScreenCurrentActiveCall(); diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 46481cad6..857596475 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -106,12 +106,15 @@ Panel::Panel(not_null call) Panel::~Panel() = default; -bool Panel::isActive() const { - return window()->isActiveWindow() - && window()->isVisible() +bool Panel::isVisible() const { + return window()->isVisible() && !(window()->windowState() & Qt::WindowMinimized); } +bool Panel::isActive() const { + return window()->isActiveWindow() && isVisible(); +} + void Panel::showAndActivate() { if (window()->isHidden()) { window()->show(); diff --git a/Telegram/SourceFiles/calls/calls_panel.h b/Telegram/SourceFiles/calls/calls_panel.h index 16836db62..dc715584a 100644 --- a/Telegram/SourceFiles/calls/calls_panel.h +++ b/Telegram/SourceFiles/calls/calls_panel.h @@ -61,6 +61,7 @@ public: Panel(not_null call); ~Panel(); + [[nodiscard]] bool isVisible() const; [[nodiscard]] bool isActive() const; void showAndActivate(); void minimize(); diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index 6002963a9..d3bac6aeb 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -258,12 +258,15 @@ not_null Panel::call() const { return _call; } -bool Panel::isActive() const { - return window()->isActiveWindow() - && window()->isVisible() +bool Panel::isVisible() const { + return window()->isVisible() && !(window()->windowState() & Qt::WindowMinimized); } +bool Panel::isActive() const { + return window()->isActiveWindow() && isVisible(); +} + base::weak_ptr Panel::showToast( const QString &text, crl::time duration) { diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.h b/Telegram/SourceFiles/calls/group/calls_group_panel.h index cf9352697..851cc91d8 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.h +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.h @@ -91,6 +91,7 @@ public: [[nodiscard]] not_null widget() const; [[nodiscard]] not_null call() const; + [[nodiscard]] bool isVisible() const; [[nodiscard]] bool isActive() const; base::weak_ptr showToast( diff --git a/Telegram/SourceFiles/platform/mac/specific_mac_p.mm b/Telegram/SourceFiles/platform/mac/specific_mac_p.mm index e02930c1a..984643871 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac_p.mm +++ b/Telegram/SourceFiles/platform/mac/specific_mac_p.mm @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwindow.h" #include "mainwidget.h" +#include "calls/calls_instance.h" #include "core/sandbox.h" #include "core/application.h" #include "core/core_settings.h" @@ -175,7 +176,11 @@ ApplicationDelegate *_sharedDelegate = nil; Core::App().handleAppActivated(); if (const auto window = Core::App().activeWindow()) { if (window->widget()->isHidden()) { - window->widget()->showFromTray(); + if (Core::App().calls().hasVisiblePanel()) { + Core::App().calls().activateCurrentCall(); + } else { + window->widget()->showFromTray(); + } } } } From a7b60c43b5419b9d212e23c08c8342a7e7e47f59 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 22:24:42 +0400 Subject: [PATCH 37/44] Version 4.11.2. - Highlight quoted parts in jump-to-message from replies. - Ctrl+Click on message field reply bar to jump to message. - Fix empty link preview displaying when generation failed. - Fix external replies in topic groups. - Allow enabling legacy tray icon on Windows. --- 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 | 8 ++++++++ 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 1422235cb..69b1a79d1 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ + Version="4.11.2.0" /> Telegram Desktop Telegram Messenger LLP diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 5b638b602..4bb6bc8bd 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,11,1,0 - PRODUCTVERSION 4,11,1,0 + FILEVERSION 4,11,2,0 + PRODUCTVERSION 4,11,2,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "4.11.1.0" + VALUE "FileVersion", "4.11.2.0" VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.11.1.0" + VALUE "ProductVersion", "4.11.2.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 5903ca8d0..527dddaa0 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,11,1,0 - PRODUCTVERSION 4,11,1,0 + FILEVERSION 4,11,2,0 + PRODUCTVERSION 4,11,2,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -53,10 +53,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "4.11.1.0" + VALUE "FileVersion", "4.11.2.0" VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.11.1.0" + VALUE "ProductVersion", "4.11.2.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 8bdb91ffd..0d5d36bb2 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 = 4011001; -constexpr auto AppVersionStr = "4.11.1"; +constexpr auto AppVersion = 4011002; +constexpr auto AppVersionStr = "4.11.2"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index de406d1d2..9137ea6e5 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 4011001 +AppVersion 4011002 AppVersionStrMajor 4.11 -AppVersionStrSmall 4.11.1 -AppVersionStr 4.11.1 +AppVersionStrSmall 4.11.2 +AppVersionStr 4.11.2 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 4.11.1 +AppVersionOriginal 4.11.2 diff --git a/changelog.txt b/changelog.txt index c201151d7..85f37f8be 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,11 @@ +4.11.2 (01.11.23) + +- Highlight quoted parts in jump-to-message from replies. +- Ctrl+Click on message field reply bar to jump to message. +- Fix empty link preview displaying when generation failed. +- Fix external replies in topic groups. +- Allow enabling legacy tray icon on Windows. + 4.11.1 (29.10.23) - Fix crash in emoji status select. From 7808cc6d41557cd81fe2dc8cd92cafd6c455740f Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 1 Nov 2023 22:57:36 +0400 Subject: [PATCH 38/44] Version 4.11.2: Fix build with Xcode. --- Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp index 3c045f29c..5a4bc0a93 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp @@ -1540,7 +1540,7 @@ void AttachWebView::confirmAddToMenu( const auto disclaimer = !disclaimerAccepted(bot); const auto done = [=](Fn close) { const auto state = (disclaimer - || (*allowed) && (*allowed)->checked()) + || ((*allowed) && (*allowed)->checked())) ? ToggledState::AllowedToWrite : ToggledState::Added; toggleInMenu(bot.user, state, [=] { From d031046edbdaa5c9c4144a40a4b117caae9d169a Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 2 Nov 2023 00:06:42 +0400 Subject: [PATCH 39/44] Version 4.11.2: Fix build with GCC. --- Telegram/SourceFiles/history/view/history_view_list_widget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index a1783dae2..410b1a337 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2577,7 +2577,6 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { : _overElement ? _overElement->data().get() : nullptr; - const auto overItemView = viewForItem(overItem); const auto clickedReaction = link ? link->property( kReactionsCountEmojiProperty).value() From 8ebf329cd98922a16adc4d0ab55230f877d75578 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 2 Nov 2023 16:44:20 +0400 Subject: [PATCH 40/44] Display group / channel id in profile. --- .../SourceFiles/info/profile/info_profile_actions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index 404b82e71..4be3f5574 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -558,11 +558,11 @@ object_ptr DetailsFiller::setupInfo() { ).text->setLinksTrusted(); } - const auto about = addInfoLine( - tr::lng_info_about_label(), - _topic ? rpl::single(TextWithEntities()) : AboutValue(_peer)); + const auto about = addInfoLine(tr::lng_info_about_label(), _topic + ? rpl::single(TextWithEntities()) + : AboutWithIdValue(_peer)); if (!_topic) { - addTranslateToMenu(about.text, AboutValue(_peer)); + addTranslateToMenu(about.text, AboutWithIdValue(_peer)); } } if (!_peer->isSelf()) { From b41c94be290d3991a37fc6470abfde13c18ea7b9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 2 Nov 2023 16:44:41 +0400 Subject: [PATCH 41/44] Fix crash in link preview edit. --- .../history/view/controls/history_view_draft_options.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp index 3438ab15d..65a1cd6de 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp @@ -638,10 +638,11 @@ void DraftOptionsBox( const auto &highlight = args.highlight; const auto &clearOldDraft = args.clearOldDraft; const auto resolveReply = [=] { - const auto current = state->quote.current(); auto result = draft.reply; - result.messageId = current.item->fullId(); - result.quote = current.text; + if (const auto current = state->quote.current()) { + result.messageId = current.item->fullId(); + result.quote = current.text; + } return result; }; const auto finish = [=]( From 8927a1b9a20a52fa673943cf1552fe94673eb00f Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 2 Nov 2023 19:58:07 +0400 Subject: [PATCH 42/44] Fix media caption adding link in replies/scheduled. --- .../history/view/controls/history_view_compose_controls.cpp | 5 +++++ 1 file changed, 5 insertions(+) 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 d2da74625..21ce63e1a 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -1940,6 +1940,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) { _header->replyToMessage({}); if (_preview) { _preview->apply({ .removed = true }); + _preview->setDisabled(false); } _canReplaceMedia = false; _photoEditMedia = nullptr; @@ -1978,6 +1979,7 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) { _preview->apply( Data::WebPageDraft::FromItem(item), false); + _preview->setDisabled(media && !media->webpage()); } return true; } @@ -2009,6 +2011,9 @@ void ComposeControls::applyDraft(FieldHistoryAction fieldHistoryAction) { cancelForward(); } _header->editMessage({}); + if (_preview) { + _preview->setDisabled(false); + } } } From 01d986403690ec6d8d619355ae8ed98761b404e1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 2 Nov 2023 20:29:35 +0400 Subject: [PATCH 43/44] Workaround crash in statistics. --- Telegram/SourceFiles/statistics/chart_widget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/statistics/chart_widget.cpp b/Telegram/SourceFiles/statistics/chart_widget.cpp index a6a167185..cead2c80f 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.cpp +++ b/Telegram/SourceFiles/statistics/chart_widget.cpp @@ -1018,9 +1018,9 @@ void ChartWidget::updateBottomDates() { const auto k = _chartArea->width() / d; const auto stepRaw = int(k / 6); + const auto by = int(_chartArea->width() / float64(_chartData.x.size())); _bottomLine.captionIndicesOffset = 0 - + st::statisticsChartBottomCaptionMaxWidth - / int(_chartArea->width() / float64(_chartData.x.size())); + + st::statisticsChartBottomCaptionMaxWidth / std::max(by, 1); const auto isCurrentNull = (_bottomLine.current.stepMinFast == 0); if (!isCurrentNull From 9e10a80e00b3c08d998c62b0023cab30301d90ae Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 2 Nov 2023 20:31:53 +0400 Subject: [PATCH 44/44] Version 4.11.3. - Fix adding a link to media captions in scheduled / comments. - Fix crash in link preview options saving. - Fix possible crash in statistics. --- 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 69b1a79d1..cc75e489e 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ + Version="4.11.3.0" /> Telegram Desktop Telegram Messenger LLP diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 4bb6bc8bd..6913bae35 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,11,2,0 - PRODUCTVERSION 4,11,2,0 + FILEVERSION 4,11,3,0 + PRODUCTVERSION 4,11,3,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.11.2.0" + VALUE "FileVersion", "4.11.3.0" VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.11.2.0" + VALUE "ProductVersion", "4.11.3.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 527dddaa0..c1d26ca21 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,11,2,0 - PRODUCTVERSION 4,11,2,0 + FILEVERSION 4,11,3,0 + PRODUCTVERSION 4,11,3,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.11.2.0" + VALUE "FileVersion", "4.11.3.0" VALUE "LegalCopyright", "Copyright (C) 2014-2023" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "4.11.2.0" + VALUE "ProductVersion", "4.11.3.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 0d5d36bb2..4003c2647 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 = 4011002; -constexpr auto AppVersionStr = "4.11.2"; +constexpr auto AppVersion = 4011003; +constexpr auto AppVersionStr = "4.11.3"; constexpr auto AppBetaVersion = false; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 9137ea6e5..1c347fd92 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 4011002 +AppVersion 4011003 AppVersionStrMajor 4.11 -AppVersionStrSmall 4.11.2 -AppVersionStr 4.11.2 +AppVersionStrSmall 4.11.3 +AppVersionStr 4.11.3 BetaChannel 0 AlphaVersion 0 -AppVersionOriginal 4.11.2 +AppVersionOriginal 4.11.3 diff --git a/changelog.txt b/changelog.txt index 85f37f8be..b053efcf0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,9 @@ +4.11.3 (02.11.23) + +- Fix adding a link to media captions in scheduled / comments. +- Fix crash in link preview options saving. +- Fix possible crash in statistics. + 4.11.2 (01.11.23) - Highlight quoted parts in jump-to-message from replies.