From e5c2133446f7c52538834920e5611f8e2f373c11 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 1 Sep 2024 17:18:17 +0300 Subject: [PATCH 01/41] Disabled Qt build on Windows without successful applied patches. --- Telegram/build/prepare/prepare.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Telegram/build/prepare/prepare.py b/Telegram/build/prepare/prepare.py index dc640093db84c1..ac027ffab8071c 100644 --- a/Telegram/build/prepare/prepare.py +++ b/Telegram/build/prepare/prepare.py @@ -457,7 +457,7 @@ def runStages(): stage('patches', """ git clone https://github.com/desktop-app/patches.git cd patches - git checkout ac72a4f597 + git checkout 8cd00d57c7 """) stage('msys64', """ @@ -1539,11 +1539,19 @@ def runStages(): stage('qt_' + qt, """ git clone -b v$QT-lts-lgpl https://github.com/qt/qt5.git qt_$QT cd qt_$QT - git submodule update --init --recursive qtbase qtimageformats qtsvg + git submodule update --init --recursive --progress qtbase qtimageformats qtsvg depends:patches/qtbase_""" + qt + """/*.patch cd qtbase win: - for /r %%i in (..\\..\\patches\\qtbase_%QT%\\*) do git apply %%i -v + setlocal enabledelayedexpansion + for /r %%i in (..\\..\\patches\\qtbase_%QT%\\*) do ( + git apply %%i -v + if errorlevel 1 ( + echo ERROR: Applying patch %%~nxi failed! + exit /b 1 + ) + ) + cd .. SET CONFIGURATIONS=-debug From 8cd5e51982465c74dfc6fa8e7d70b327d7878a2f Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 1 Sep 2024 22:16:25 +0300 Subject: [PATCH 02/41] Added missed handler of server error when try to reset cloud password. --- Telegram/SourceFiles/api/api_cloud_password.cpp | 5 ----- .../settings_cloud_password_input.cpp | 13 ++++++++++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Telegram/SourceFiles/api/api_cloud_password.cpp b/Telegram/SourceFiles/api/api_cloud_password.cpp index 8995b119141ce2..e974154b989cb3 100644 --- a/Telegram/SourceFiles/api/api_cloud_password.cpp +++ b/Telegram/SourceFiles/api/api_cloud_password.cpp @@ -81,11 +81,6 @@ auto CloudPassword::stateCurrent() const auto CloudPassword::resetPassword() -> rpl::producer { return [=](auto consumer) { - base::call_delayed(3000, [=] { - consumer.put_next_copy(base::unixtime::now() + 86400); - consumer.put_done(); - }); - return rpl::lifetime(); _api.request(MTPaccount_ResetPassword( )).done([=](const MTPaccount_ResetPasswordResult &result) { result.match([&](const MTPDaccount_resetPasswordOk &data) { diff --git a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp index 2321287d7b5287..fc16b817998ace 100644 --- a/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp +++ b/Telegram/SourceFiles/settings/cloud_password/settings_cloud_password_input.cpp @@ -263,7 +263,18 @@ void Input::setupContent() { } close(); _requestLifetime = cloudPassword().resetPassword( - ) | rpl::start_with_error_done([=](const QString &type) { + ) | rpl::start_with_next_error_done([=]( + Api::CloudPassword::ResetRetryDate retryDate) { + _requestLifetime.destroy(); + const auto left = std::max( + retryDate - base::unixtime::now(), + 60); + controller()->show(Ui::MakeInformBox( + tr::lng_cloud_password_reset_later( + tr::now, + lt_duration, + Ui::FormatResetCloudPasswordIn(left)))); + }, [=](const QString &type) { _requestLifetime.destroy(); }, [=] { _requestLifetime.destroy(); From 8aa7499e63599b2ae712d246e0b8ea2f75b69154 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 1 Sep 2024 23:29:21 +0300 Subject: [PATCH 03/41] Fixed width of stats PointDetailsWidget for charts with currency. --- .../SourceFiles/statistics/chart_widget.cpp | 8 --- .../widgets/point_details_widget.cpp | 50 +++++++++++++++++-- .../statistics/widgets/point_details_widget.h | 1 - 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/Telegram/SourceFiles/statistics/chart_widget.cpp b/Telegram/SourceFiles/statistics/chart_widget.cpp index 823481e6b7a923..4e7534d9a3f19a 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.cpp +++ b/Telegram/SourceFiles/statistics/chart_widget.cpp @@ -1156,20 +1156,12 @@ void ChartWidget::setupDetails() { _chartArea->update(); return; } - const auto maxAbsoluteValue = [&] { - auto maxValue = ChartValue(0); - for (const auto &l : _chartData.lines) { - maxValue = std::max(l.maxValue, maxValue); - } - return maxValue; - }(); if (hasLocalZoom()) { _zoomEnabled = true; } _details.widget = base::make_unique_q( this, _chartData, - maxAbsoluteValue, _zoomEnabled); _details.widget->setClickedCallback([=] { const auto index = _details.widget->xIndex(); diff --git a/Telegram/SourceFiles/statistics/widgets/point_details_widget.cpp b/Telegram/SourceFiles/statistics/widgets/point_details_widget.cpp index f96c4ac3a5af47..dc0668e9aab93b 100644 --- a/Telegram/SourceFiles/statistics/widgets/point_details_widget.cpp +++ b/Telegram/SourceFiles/statistics/widgets/point_details_widget.cpp @@ -130,7 +130,6 @@ void PaintDetails( PointDetailsWidget::PointDetailsWidget( not_null parent, const Data::StatisticalChart &chartData, - float64 maxAbsoluteValue, bool zoomEnabled) : Ui::AbstractButton(parent) , _zoomEnabled(zoomEnabled) @@ -173,12 +172,44 @@ PointDetailsWidget::PointDetailsWidget( return 0; }(); - const auto calculatedWidth = [&]{ + const auto hasUsdLine = (_chartData.currencyRate != 0) + && (_chartData.currency != Data::StatisticalCurrency::None) + && (_chartData.lines.size() == 1); + + const auto maxValueTextWidth = [&] { + if (hasUsdLine) { + auto maxValueWidth = 0; + const auto multiplier = float64(Data::kEarnMultiplier); + for (const auto &value : _chartData.lines.front().y) { + const auto valueText = Ui::Text::String( + _textStyle, + QString::number(value / multiplier)); + const auto usdText = Ui::Text::String( + _textStyle, + Info::ChannelEarn::ToUsd(value, _chartData.currencyRate)); + const auto width = std::max( + usdText.maxWidth(), + valueText.maxWidth()); + if (width > maxValueWidth) { + maxValueWidth = width; + } + } + return maxValueWidth; + } + const auto maxAbsoluteValue = [&] { + auto maxValue = ChartValue(0); + for (const auto &l : _chartData.lines) { + maxValue = std::max(l.maxValue, maxValue); + } + return maxValue; + }(); const auto maxValueText = Ui::Text::String( _textStyle, Lang::FormatCountDecimal(maxAbsoluteValue)); - const auto maxValueTextWidth = maxValueText.maxWidth(); + return maxValueText.maxWidth(); + }(); + const auto calculatedWidth = [&]{ auto maxNameTextWidth = 0; for (const auto &dataLine : _chartData.lines) { const auto maxNameText = Ui::Text::String( @@ -187,6 +218,19 @@ PointDetailsWidget::PointDetailsWidget( maxNameTextWidth = std::max( maxNameText.maxWidth(), maxNameTextWidth); + if (hasUsdLine) { + const auto currency = Ui::Text::String( + _textStyle, + tr::lng_channel_earn_chart_overriden_detail_currency( + tr::now)); + const auto usd = Ui::Text::String( + _textStyle, + tr::lng_channel_earn_chart_overriden_detail_usd( + tr::now)); + maxNameTextWidth = std::max( + std::max(currency.maxWidth(), usd.maxWidth()), + maxNameTextWidth); + } } { const auto maxHeaderText = Ui::Text::String( diff --git a/Telegram/SourceFiles/statistics/widgets/point_details_widget.h b/Telegram/SourceFiles/statistics/widgets/point_details_widget.h index cdf6b3bd3acc29..7d6a39b90717d4 100644 --- a/Telegram/SourceFiles/statistics/widgets/point_details_widget.h +++ b/Telegram/SourceFiles/statistics/widgets/point_details_widget.h @@ -27,7 +27,6 @@ class PointDetailsWidget : public Ui::AbstractButton { PointDetailsWidget( not_null parent, const Data::StatisticalChart &chartData, - float64 maxAbsoluteValue, bool zoomEnabled); [[nodiscard]] int xIndex() const; From 5ac80d2655c650644913cc96d053ed668a49793c Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 1 Sep 2024 23:33:52 +0300 Subject: [PATCH 04/41] Fixed text clipping at bottom in settings section for cloud password. --- Telegram/SourceFiles/settings/settings.style | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index df59546a66629d..094af51db5062c 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -176,7 +176,7 @@ settingLocalPasscodeInputField: InputField(defaultInputField) { settingLocalPasscodeDescription: FlatLabel(changePhoneDescription) { minWidth: 256px; } -settingLocalPasscodeDescriptionHeight: 52px; +settingLocalPasscodeDescriptionHeight: 53px; settingLocalPasscodeError: FlatLabel(changePhoneError) { minWidth: 256px; } From 2b502b22b9c1f0d76407627955009a9ea03e3ed3 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 1 Sep 2024 23:38:56 +0300 Subject: [PATCH 05/41] Replaced PeerData::generateUserpicImage with static function. --- Telegram/SourceFiles/api/api_who_reacted.cpp | 5 ++++- .../boxes/peers/prepare_short_info_box.cpp | 3 ++- .../group/calls_group_viewport_opengl.cpp | 3 ++- .../group/calls_group_viewport_raster.cpp | 3 ++- Telegram/SourceFiles/data/data_peer.cpp | 20 ++++++++++--------- Telegram/SourceFiles/data/data_peer.h | 5 +++-- .../SourceFiles/data/data_peer_values.cpp | 10 ++++++---- Telegram/SourceFiles/dialogs/dialogs_row.cpp | 2 +- .../view/history_view_group_call_bar.cpp | 3 ++- .../view/history_view_requests_bar.cpp | 3 ++- .../stories/media_stories_recent_views.cpp | 9 ++++++--- .../media/stories/media_stories_sibling.cpp | 5 ++++- .../settings/settings_websites.cpp | 3 ++- .../ui/controls/userpic_button.cpp | 6 ++++-- .../SourceFiles/ui/dynamic_thumbnails.cpp | 6 +++++- .../window/notifications_utilities.cpp | 2 +- 16 files changed, 57 insertions(+), 31 deletions(-) diff --git a/Telegram/SourceFiles/api/api_who_reacted.cpp b/Telegram/SourceFiles/api/api_who_reacted.cpp index f610f833daeba0..6c9df39b2d9503 100644 --- a/Telegram/SourceFiles/api/api_who_reacted.cpp +++ b/Telegram/SourceFiles/api/api_who_reacted.cpp @@ -214,7 +214,10 @@ struct State { [[nodiscard]] QImage GenerateUserpic(Userpic &userpic, int size) { size *= style::DevicePixelRatio(); - auto result = userpic.peer->generateUserpicImage(userpic.view, size); + auto result = PeerData::GenerateUserpicImage( + userpic.peer, + userpic.view, + size); result.setDevicePixelRatio(style::DevicePixelRatio()); return result; } diff --git a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp index 6c19d4055e2a12..363a2e9dc72717 100644 --- a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp @@ -79,7 +79,8 @@ void ProcessUserpic( if (!state->userpicView.cloud) { GenerateImage( state, - peer->generateUserpicImage( + PeerData::GenerateUserpicImage( + peer, state->userpicView, st::shortInfoWidth * style::DevicePixelRatio(), 0), diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp index 6f6b076204b687..9af2a36f47434e 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp @@ -460,7 +460,8 @@ void Viewport::RendererGL::validateUserpicFrame( return; } const auto size = tile->trackOrUserpicSize(); - tileData.userpicFrame = tile->row()->peer()->generateUserpicImage( + tileData.userpicFrame = PeerData::GenerateUserpicImage( + tile->row()->peer(), tile->row()->ensureUserpicView(), size.width(), 0); diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp index ab335c55c77047..e8aa42ad810dca 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_raster.cpp @@ -77,7 +77,8 @@ void Viewport::RendererSW::validateUserpicFrame( } const auto size = tile->trackOrUserpicSize(); data.userpicFrame = Images::BlurLargeImage( - tile->row()->peer()->generateUserpicImage( + PeerData::GenerateUserpicImage( + tile->row()->peer(), tile->row()->ensureUserpicView(), size.width(), 0), diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 097cfdfa83e2d3..bf3a7c84cf20f2 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -437,11 +437,12 @@ InMemoryKey PeerData::userpicUniqueKey(Ui::PeerUserpicView &view) const { : inMemoryKey(_userpic.location()); } -QImage PeerData::generateUserpicImage( +QImage PeerData::GenerateUserpicImage( + not_null peer, Ui::PeerUserpicView &view, int size, - std::optional radius) const { - if (const auto userpic = userpicCloudImage(view)) { + std::optional radius) { + if (const auto userpic = peer->userpicCloudImage(view)) { auto image = userpic->scaled( { size, size }, Qt::IgnoreAspectRatio, @@ -455,7 +456,7 @@ QImage PeerData::generateUserpicImage( return image; } else if (radius) { return round(*radius); - } else if (isForum()) { + } else if (peer->isForum()) { return round(size * Ui::ForumUserpicRadiusMultiplier()); } else { return Images::Circle(std::move(image)); @@ -468,11 +469,12 @@ QImage PeerData::generateUserpicImage( Painter p(&result); if (radius == 0) { - ensureEmptyUserpic()->paintSquare(p, 0, 0, size, size); + peer->ensureEmptyUserpic()->paintSquare(p, 0, 0, size, size); } else if (radius) { - ensureEmptyUserpic()->paintRounded(p, 0, 0, size, size, *radius); - } else if (isForum()) { - ensureEmptyUserpic()->paintRounded( + const auto r = *radius; + peer->ensureEmptyUserpic()->paintRounded(p, 0, 0, size, size, r); + } else if (peer->isForum()) { + peer->ensureEmptyUserpic()->paintRounded( p, 0, 0, @@ -480,7 +482,7 @@ QImage PeerData::generateUserpicImage( size, size * Ui::ForumUserpicRadiusMultiplier()); } else { - ensureEmptyUserpic()->paintCircle(p, 0, 0, size, size); + peer->ensureEmptyUserpic()->paintCircle(p, 0, 0, size, size); } p.end(); diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index f88d801cea846b..d252b0c01e8907 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -333,10 +333,11 @@ class PeerData { [[nodiscard]] Ui::PeerUserpicView createUserpicView(); [[nodiscard]] bool useEmptyUserpic(Ui::PeerUserpicView &view) const; [[nodiscard]] InMemoryKey userpicUniqueKey(Ui::PeerUserpicView &view) const; - [[nodiscard]] QImage generateUserpicImage( + [[nodiscard]] static QImage GenerateUserpicImage( + not_null peer, Ui::PeerUserpicView &view, int size, - std::optional radius = {}) const; + std::optional radius = {}); [[nodiscard]] ImageLocation userpicLocation() const; static constexpr auto kUnknownPhotoId = PhotoId(0xFFFFFFFFFFFFFFFFULL); diff --git a/Telegram/SourceFiles/data/data_peer_values.cpp b/Telegram/SourceFiles/data/data_peer_values.cpp index 92c1f1d95ac4cb..c5e26bb0f23114 100644 --- a/Telegram/SourceFiles/data/data_peer_values.cpp +++ b/Telegram/SourceFiles/data/data_peer_values.cpp @@ -542,10 +542,12 @@ rpl::producer PeerUserpicImageValue( } state->key = key; state->empty = false; - consumer.put_next(peer->generateUserpicImage( - state->view, - size, - radius)); + consumer.put_next( + PeerData::GenerateUserpicImage( + peer, + state->view, + size, + radius)); }; peer->session().changes().peerFlagsValue( peer, diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 650b4cf9377665..5a0730f86d96b6 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -118,7 +118,7 @@ constexpr auto kBlurRadius = 24; const auto &partSize = partRect.width(); const auto partSkip = fullSize - partSize; auto result = Images::Circle(BlurredDarkenedPart( - peer->generateUserpicImage(view, fullSize * ratio, 0), + PeerData::GenerateUserpicImage(peer, view, fullSize * ratio, 0), QRect( QPoint(partSkip, partSkip) * ratio, QSize(partSize, partSize) * ratio))); diff --git a/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp b/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp index 0b978acb388b78..1406b7e5ba1fd1 100644 --- a/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp +++ b/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp @@ -142,7 +142,8 @@ rpl::producer GroupCallBarContentByCall( state->someUserpicsNotLoaded = false; for (auto &userpic : state->userpics) { userpic.peer->loadUserpic(); - auto image = userpic.peer->generateUserpicImage( + auto image = PeerData::GenerateUserpicImage( + userpic.peer, userpic.view, userpicSize * style::DevicePixelRatio()); userpic.uniqueKey = userpic.peer->userpicUniqueKey(userpic.view); diff --git a/Telegram/SourceFiles/history/view/history_view_requests_bar.cpp b/Telegram/SourceFiles/history/view/history_view_requests_bar.cpp index 6c3fc478a28597..e10a50b8a7b584 100644 --- a/Telegram/SourceFiles/history/view/history_view_requests_bar.cpp +++ b/Telegram/SourceFiles/history/view/history_view_requests_bar.cpp @@ -86,7 +86,8 @@ rpl::producer RequestsBarContentByPeer( state->someUserpicsNotLoaded = false; for (auto &userpic : state->userpics) { userpic.peer->loadUserpic(); - auto image = userpic.peer->generateUserpicImage( + auto image = PeerData::GenerateUserpicImage( + userpic.peer, userpic.view, userpicSize * style::DevicePixelRatio()); userpic.uniqueKey = userpic.peer->userpicUniqueKey(userpic.view); diff --git a/Telegram/SourceFiles/media/stories/media_stories_recent_views.cpp b/Telegram/SourceFiles/media/stories/media_stories_recent_views.cpp index e6b53d2777551d..66456372583f30 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_recent_views.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_recent_views.cpp @@ -54,7 +54,8 @@ constexpr auto kLoadViewsPages = 2; static const auto size = st::storiesWhoViewed.userpics.size; static const auto GenerateUserpic = [](Userpic &userpic) { - auto result = userpic.peer->generateUserpicImage( + auto result = PeerData::GenerateUserpicImage( + userpic.peer, userpic.view, size * style::DevicePixelRatio()); result.setDevicePixelRatio(style::DevicePixelRatio()); @@ -522,7 +523,8 @@ void RecentViews::addMenuRow(Data::StoryView entry, const QDateTime &now) { const auto show = _controller->uiShow(); const auto prepare = [&](Ui::PeerUserpicView &view) { const auto size = st::storiesWhoViewed.photoSize; - auto userpic = peer->generateUserpicImage( + auto userpic = PeerData::GenerateUserpicImage( + peer, view, size * style::DevicePixelRatio()); userpic.setDevicePixelRatio(style::DevicePixelRatio()); @@ -636,7 +638,8 @@ void RecentViews::subscribeToMenuUserpicsLoading( const auto update = (entry.key != key); if (update) { const auto size = st::storiesWhoViewed.photoSize; - auto userpic = peer->generateUserpicImage( + auto userpic = PeerData::GenerateUserpicImage( + peer, view, size * style::DevicePixelRatio()); userpic.setDevicePixelRatio(style::DevicePixelRatio()); diff --git a/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp b/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp index 74263985125b98..6e4947ece53803 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp @@ -336,7 +336,10 @@ QImage Sibling::userpicImage(const SiblingLayout &layout) { const auto key = _peer->userpicUniqueKey(_userpicView); if (_userpicImage.width() != size || _userpicKey != key) { _userpicKey = key; - _userpicImage = _peer->generateUserpicImage(_userpicView, size); + _userpicImage = PeerData::GenerateUserpicImage( + _peer, + _userpicView, + size); _userpicImage.setDevicePixelRatio(ratio); } return _userpicImage; diff --git a/Telegram/SourceFiles/settings/settings_websites.cpp b/Telegram/SourceFiles/settings/settings_websites.cpp index bff91b15542749..55bf911dab592e 100644 --- a/Telegram/SourceFiles/settings/settings_websites.cpp +++ b/Telegram/SourceFiles/settings/settings_websites.cpp @@ -235,7 +235,8 @@ PaintRoundImageCallback Row::generatePaintUserpicCallback(bool forceRound) { p.drawImage(QRect(x, y, size, size), userpic.cached); } else { if (_emptyUserpic.isNull()) { - _emptyUserpic = peer->generateUserpicImage( + _emptyUserpic = PeerData::GenerateUserpicImage( + peer, _userpic, size * ratio, size * ratio * Ui::ForumUserpicRadiusMultiplier()); diff --git a/Telegram/SourceFiles/ui/controls/userpic_button.cpp b/Telegram/SourceFiles/ui/controls/userpic_button.cpp index 2ee400c1e3067c..ea0bfa937cbe4d 100644 --- a/Telegram/SourceFiles/ui/controls/userpic_button.cpp +++ b/Telegram/SourceFiles/ui/controls/userpic_button.cpp @@ -1026,10 +1026,12 @@ void UserpicButton::prepareUserpicPixmap() { true); p.drawImage(QRect(0, 0, size, size), _userpicView.cached); } else { - const auto empty = _peer->generateUserpicImage( + const auto empty = PeerData::GenerateUserpicImage( + _peer, _userpicView, size * ratio, - size * ratio * Ui::ForumUserpicRadiusMultiplier()); + (size * ratio) + * Ui::ForumUserpicRadiusMultiplier()); p.drawImage(QRect(0, 0, size, size), empty); } } else { diff --git a/Telegram/SourceFiles/ui/dynamic_thumbnails.cpp b/Telegram/SourceFiles/ui/dynamic_thumbnails.cpp index bd2ed0b1459710..868e95cb549752 100644 --- a/Telegram/SourceFiles/ui/dynamic_thumbnails.cpp +++ b/Telegram/SourceFiles/ui/dynamic_thumbnails.cpp @@ -245,7 +245,11 @@ QImage PeerUserpic::image(int size) { } else { const auto full = size * style::DevicePixelRatio(); const auto r = full / 2.; - const auto empty = _peer->generateUserpicImage(view, full, r); + const auto empty = PeerData::GenerateUserpicImage( + _peer, + view, + full, + r); p.drawImage(QRect(0, 0, size, size), empty); } } diff --git a/Telegram/SourceFiles/window/notifications_utilities.cpp b/Telegram/SourceFiles/window/notifications_utilities.cpp index 418848c0554cd0..e2ef49fed2d1d9 100644 --- a/Telegram/SourceFiles/window/notifications_utilities.cpp +++ b/Telegram/SourceFiles/window/notifications_utilities.cpp @@ -28,7 +28,7 @@ QImage GenerateUserpic(not_null peer, Ui::PeerUserpicView &view) { ? Ui::EmptyUserpic::GenerateSavedMessages(st::notifyMacPhotoSize) : peer->isRepliesChat() ? Ui::EmptyUserpic::GenerateRepliesMessages(st::notifyMacPhotoSize) - : peer->generateUserpicImage(view, st::notifyMacPhotoSize); + : PeerData::GenerateUserpicImage(peer, view, st::notifyMacPhotoSize); } CachedUserpics::CachedUserpics() From fb8b88557e081d176e726814626ce812a9ebfa44 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 2 Sep 2024 00:20:53 +0300 Subject: [PATCH 06/41] Added ability to kick participants from section of admin log. --- Telegram/Resources/langs/lang.strings | 1 + .../admin_log/history_admin_log_inner.cpp | 27 +++++++++++++++++++ Telegram/SourceFiles/ui/menu_icons.style | 1 + 3 files changed, 29 insertions(+) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index b6701988bb138f..82e5dfb6820439 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3349,6 +3349,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_context_promote_admin" = "Promote to admin"; "lng_context_edit_permissions" = "Edit permissions"; "lng_context_restrict_user" = "Restrict user"; +"lng_context_ban_user" = "Ban"; "lng_context_remove_from_group" = "Remove from group"; "lng_context_add_to_group" = "Add to group"; 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 08631701fe9e53..a53de982aaf379 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -39,6 +39,8 @@ For license and copyright information please follow this link: #include "ui/chat/chat_style.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/expandable_peer_list.h" +#include "ui/widgets/menu/menu_add_action_callback_factory.h" +#include "ui/widgets/menu/menu_add_action_callback.h" #include "ui/widgets/popup_menu.h" #include "ui/image/image.h" #include "ui/text/text_utilities.h" @@ -52,6 +54,7 @@ For license and copyright information please follow this link: #include "lang/lang_keys.h" #include "boxes/peers/edit_participant_box.h" #include "boxes/peers/edit_participants_box.h" +#include "data/data_changes.h" #include "data/data_session.h" #include "data/data_photo.h" #include "data/data_photo_media.h" @@ -1564,6 +1567,30 @@ void InnerWidget::suggestRestrictParticipant( }).send(); } }, &st::menuIconPermissions); + + { + const auto lifetime = std::make_shared(); + auto handler = [=, this] { + participant->session().changes().peerUpdates( + _channel, + Data::PeerUpdate::Flag::Members + ) | rpl::start_with_next([=](const Data::PeerUpdate &update) { + _downLoaded = false; + preloadMore(Direction::Down); + lifetime->destroy(); + }, *lifetime); + participant->session().api().chatParticipants().kick( + _channel, + participant, + { _channel->restrictions(), 0 }); + }; + Ui::Menu::CreateAddActionCallback(_menu)({ + .text = tr::lng_context_ban_user(tr::now), + .handler = std::move(handler), + .icon = &st::menuIconBlockAttention, + .isAttention = true, + }); + } } void InnerWidget::restrictParticipant( diff --git a/Telegram/SourceFiles/ui/menu_icons.style b/Telegram/SourceFiles/ui/menu_icons.style index ebe25e46b651f3..80a9ed4ad6a993 100644 --- a/Telegram/SourceFiles/ui/menu_icons.style +++ b/Telegram/SourceFiles/ui/menu_icons.style @@ -203,6 +203,7 @@ menuIconReportAttention: icon {{ "menu/report", menuIconAttentionColor }}; menuIconRestoreAttention: icon {{ "menu/restore", menuIconAttentionColor }}; menuIconTagRemoveAttention: icon {{ "menu/tag_remove", menuIconAttentionColor }}; menuIconCancelAttention: icon {{ "menu/cancel", menuIconAttentionColor }}; +menuIconBlockAttention: icon {{ "menu/block", menuIconAttentionColor }}; menuIconBlockSettings: icon {{ "menu/block", windowBgActive }}; menuIconInviteSettings: icon {{ "menu/invite", windowBgActive }}; From 841f1afe1e8830a37a164907c8d511d973a4b9ff Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 2 Sep 2024 01:18:45 +0300 Subject: [PATCH 07/41] Improved subtitle space in permissions and restrictions edit boxes. --- Telegram/SourceFiles/boxes/boxes.style | 2 -- .../boxes/moderate_messages_box.cpp | 8 +++-- .../boxes/peers/edit_participant_box.cpp | 33 ++++++++++++------- .../boxes/peers/edit_participant_box.h | 2 ++ .../boxes/peers/edit_peer_permissions_box.cpp | 17 +++------- .../boxes/peers/edit_peer_permissions_box.h | 3 -- 6 files changed, 32 insertions(+), 33 deletions(-) diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index b977c1c603e235..7fb0f669a3cdc4 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -597,8 +597,6 @@ rightsHeaderLabel: FlatLabel(boxLabel) { } textFg: windowActiveTextFg; } -rightsUntilMargin: margins(0px, 8px, 0px, 20px); -rightsRankMargin: margins(0px, 7px, 0px, 20px); groupStickersRemove: defaultMultiSelectSearchCancel; groupStickersRemovePosition: point(6px, 6px); diff --git a/Telegram/SourceFiles/boxes/moderate_messages_box.cpp b/Telegram/SourceFiles/boxes/moderate_messages_box.cpp index 301da703145bfa..9c68881a1ea54e 100644 --- a/Telegram/SourceFiles/boxes/moderate_messages_box.cpp +++ b/Telegram/SourceFiles/boxes/moderate_messages_box.cpp @@ -436,14 +436,16 @@ void CreateModerateMessagesBox( return result; }(); - auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions( - box, + Ui::AddSubsectionTitle( + inner, rpl::conditional( rpl::single(isSingle), tr::lng_restrict_users_part_single_header(), tr::lng_restrict_users_part_header( lt_count, - rpl::single(participants.size()) | tr::to_count())), + rpl::single(participants.size()) | tr::to_count()))); + auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions( + box, prepareFlags, disabledMessages, { .isForum = peer->isForum() }); diff --git a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp index 39389d1d567928..23c7602f31b019 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp @@ -9,6 +9,7 @@ For license and copyright information please follow this link: #include "lang/lang_keys.h" #include "ui/controls/userpic_button.h" +#include "ui/vertical_list.h" #include "ui/wrap/vertical_layout.h" #include "ui/wrap/padding_wrap.h" #include "ui/wrap/slide_wrap.h" @@ -63,6 +64,10 @@ class EditParticipantBox::Inner : public Ui::RpWidget { template Widget *addControl(object_ptr widget, QMargins margin); + [[nodiscard]] not_null verticalLayout() const { + return _rows; + } + protected: int resizeGetHeight(int newWidth) override; void paintEvent(QPaintEvent *e) override; @@ -164,6 +169,10 @@ EditParticipantBox::EditParticipantBox( , _hasAdminRights(hasAdminRights) { } +not_null EditParticipantBox::verticalLayout() const { + return _inner->verticalLayout(); +} + void EditParticipantBox::prepare() { _inner = setInnerWidget(object_ptr( this, @@ -279,9 +288,8 @@ void EditAdminBox::prepare() { object_ptr(this))); const auto inner = _adminControlsWrap->entity(); - inner->add( - object_ptr(inner), - st::rightsDividerMargin); + Ui::AddDivider(inner); + Ui::AddSkip(inner); const auto chat = peer()->asChat(); const auto channel = peer()->asChannel(); @@ -335,9 +343,9 @@ void EditAdminBox::prepare() { .isForum = peer()->isForum(), .anyoneCanAddMembers = anyoneCanAddMembers, }; + Ui::AddSubsectionTitle(inner, tr::lng_rights_edit_admin_header()); auto [checkboxes, getChecked, changes] = CreateEditAdminRights( inner, - tr::lng_rights_edit_admin_header(), prepareFlags, disabledMessages, options); @@ -441,9 +449,7 @@ void EditAdminBox::refreshButtons() { not_null EditAdminBox::addRankInput( not_null container) { - container->add( - object_ptr(container), - st::rightsRankMargin); + Ui::AddDivider(container); container->add( object_ptr( @@ -712,9 +718,8 @@ void EditRestrictedBox::prepare() { setTitle(tr::lng_rights_user_restrictions()); - addControl( - object_ptr(this), - st::rightsDividerMargin); + Ui::AddDivider(verticalLayout()); + Ui::AddSkip(verticalLayout()); const auto chat = peer()->asChat(); const auto channel = peer()->asChannel(); @@ -749,16 +754,20 @@ void EditRestrictedBox::prepare() { return result; }(); + Ui::AddSubsectionTitle( + verticalLayout(), + tr::lng_rights_user_restrictions_header()); auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions( this, - tr::lng_rights_user_restrictions_header(), prepareFlags, disabledMessages, { .isForum = peer()->isForum() }); addControl(std::move(checkboxes), QMargins()); _until = prepareRights.until; - addControl(object_ptr(this), st::rightsUntilMargin); + addControl( + object_ptr(this, st::defaultVerticalListSkip)); + Ui::AddDivider(verticalLayout()); addControl( object_ptr( this, diff --git a/Telegram/SourceFiles/boxes/peers/edit_participant_box.h b/Telegram/SourceFiles/boxes/peers/edit_participant_box.h index 69424cbdc62476..6d9afe25a4e098 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participant_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_participant_box.h @@ -36,6 +36,8 @@ class EditParticipantBox : public Ui::BoxContent { not_null user, bool hasAdminRights); + [[nodiscard]] not_null verticalLayout() const; + protected: void prepare() override; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp index 3cb0265ba24760..4d6dbc3ec3968f 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp @@ -19,6 +19,7 @@ For license and copyright information please follow this link: #include "ui/wrap/vertical_layout.h" #include "ui/layers/generic_box.h" #include "ui/painter.h" +#include "ui/vertical_list.h" #include "ui/widgets/labels.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" @@ -583,14 +584,6 @@ template ApplyDependencies(state->checkViews, dependencies, view); }; - if (descriptor.header) { - container->add( - object_ptr( - container, - std::move(descriptor.header), - st::rightsHeaderLabel), - st::rightsHeaderMargin); - } const auto addCheckbox = [&]( not_null verticalLayout, bool isInner, @@ -1146,9 +1139,11 @@ void ShowEditPeerPermissionsBox( return result; }(); + Ui::AddSubsectionTitle( + inner, + tr::lng_rights_default_restrictions_header()); auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions( inner, - tr::lng_rights_default_restrictions_header(), restrictions, disabledMessages, { .isForum = peer->isForum() }); @@ -1312,7 +1307,6 @@ std::vector AdminRightLabels( EditFlagsControl CreateEditRestrictions( QWidget *parent, - rpl::producer header, ChatRestrictions restrictions, base::flat_map disabledMessages, Data::RestrictionsSetOptions options) { @@ -1321,7 +1315,6 @@ EditFlagsControl CreateEditRestrictions( widget.data(), NegateRestrictions(restrictions), { - .header = std::move(header), .labels = NestedRestrictionLabelsList(options), .disabledMessages = std::move(disabledMessages), }); @@ -1338,7 +1331,6 @@ EditFlagsControl CreateEditRestrictions( EditFlagsControl CreateEditAdminRights( QWidget *parent, - rpl::producer header, ChatAdminRights rights, base::flat_map disabledMessages, Data::AdminRightsSetOptions options) { @@ -1347,7 +1339,6 @@ EditFlagsControl CreateEditAdminRights( widget.data(), rights, { - .header = std::move(header), .labels = NestedAdminRightLabels(options), .disabledMessages = std::move(disabledMessages), }); diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h index b7e63e2e231d33..ce45f4e680ff75 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h @@ -73,7 +73,6 @@ struct NestedEditFlagsLabels { template struct EditFlagsDescriptor { - rpl::producer header; std::vector> labels; base::flat_map disabledMessages; const style::SettingsButton *st = nullptr; @@ -90,7 +89,6 @@ using AdminRightLabel = EditFlagsLabel; [[nodiscard]] auto CreateEditRestrictions( QWidget *parent, - rpl::producer header, ChatRestrictions restrictions, base::flat_map disabledMessages, Data::RestrictionsSetOptions options) @@ -98,7 +96,6 @@ using AdminRightLabel = EditFlagsLabel; [[nodiscard]] auto CreateEditAdminRights( QWidget *parent, - rpl::producer header, ChatAdminRights rights, base::flat_map disabledMessages, Data::AdminRightsSetOptions options) From df935e0477d0cab353dd079f68782559d441ac53 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 2 Sep 2024 01:22:26 +0300 Subject: [PATCH 08/41] Improved code style of gifMaxStatusWidth static function. --- .../history/view/media/history_view_gif.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 2d62e464d7f846..c6b5addb4155fb 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -64,9 +64,12 @@ constexpr auto kMaxGifForwardedBarLines = 4; constexpr auto kUseNonBlurredThreshold = 240; constexpr auto kMaxInlineArea = 1920 * 1080; -int gifMaxStatusWidth(DocumentData *document) { - auto result = st::normalFont->width(Ui::FormatDownloadText(document->size, document->size)); - accumulate_max(result, st::normalFont->width(Ui::FormatGifAndSizeText(document->size))); +[[nodiscard]] int GifMaxStatusWidth(not_null document) { + auto result = st::normalFont->width( + Ui::FormatDownloadText(document->size, document->size)); + accumulate_max( + result, + st::normalFont->width(Ui::FormatGifAndSizeText(document->size))); return result; } @@ -264,7 +267,10 @@ QSize Gif::countOptimalSize() { thumbMaxWidth); auto minHeight = qMax(scaled.height(), st::minPhotoSize); if (!activeCurrentStreamed()) { - accumulate_max(maxWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); + accumulate_max( + maxWidth, + GifMaxStatusWidth(_data) + + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); } if (_parent->hasBubble()) { maxWidth = qMax(maxWidth, _parent->textualMaxWidth()); @@ -298,7 +304,10 @@ QSize Gif::countCurrentSize(int newWidth) { thumbMaxWidth); auto newHeight = qMax(scaled.height(), st::minPhotoSize); if (!activeCurrentStreamed()) { - accumulate_max(newWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); + accumulate_max( + newWidth, + GifMaxStatusWidth(_data) + + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); } if (_parent->hasBubble()) { accumulate_max(newWidth, _parent->minWidthForMedia()); From f956c0f227d6d039218e15c95204faafb13dde5a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 2 Sep 2024 23:42:40 +0300 Subject: [PATCH 09/41] Added experimental option to disable touch bar on macOS. --- .../SourceFiles/platform/mac/main_window_mac.mm | 9 +++++++-- .../SourceFiles/settings/settings_experimental.cpp | 1 + Telegram/SourceFiles/window/main_window.cpp | 14 ++++++++++++++ Telegram/SourceFiles/window/main_window.h | 1 + 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index f4e49f798b019b..6d3514d3474970 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -8,7 +8,6 @@ #include "platform/mac/main_window_mac.h" #include "data/data_session.h" -#include "mainwidget.h" #include "core/application.h" #include "core/sandbox.h" #include "main/main_session.h" @@ -25,6 +24,7 @@ #include "platform/platform_specific.h" #include "platform/platform_notifications_manager.h" #include "base/platform/base_platform_info.h" +#include "base/options.h" #include "boxes/peer_list_controllers.h" #include "boxes/about_box.h" #include "lang/lang_keys.h" @@ -300,7 +300,12 @@ QString strNotificationAboutScreenUnlocked() { if (auto view = reinterpret_cast(winId())) { if (auto window = [view window]) { _private->setNativeWindow(window, view); - _private->initTouchBar(window, &controller()); + if (!base::options::lookup( + Window::kOptionDisableTouchbar).value()) { + _private->initTouchBar(window, &controller()); + } else { + LOG(("Touch Bar was disabled from Experimental Settings.")); + } } } } diff --git a/Telegram/SourceFiles/settings/settings_experimental.cpp b/Telegram/SourceFiles/settings/settings_experimental.cpp index c17eda5b8b07d1..983497e8a14de0 100644 --- a/Telegram/SourceFiles/settings/settings_experimental.cpp +++ b/Telegram/SourceFiles/settings/settings_experimental.cpp @@ -156,6 +156,7 @@ void SetupExperimental( addToggle(Core::kOptionSkipUrlSchemeRegister); addToggle(Data::kOptionExternalVideoPlayer); addToggle(Window::kOptionNewWindowsSizeAsFirst); + addToggle(Window::kOptionDisableTouchbar); } } // namespace diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index 7702952c10a1d0..208ed561cdb8ef 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -74,9 +74,23 @@ base::options::toggle OptionNewWindowsSizeAsFirst({ .description = "Open new windows with a size of the main window.", }); +base::options::toggle OptionDisableTouchbar({ + .id = kOptionDisableTouchbar, + .name = "Disable Touch Bar (macOS only).", + .scope = [] { +#ifdef Q_OS_MAC + return true; +#else // !Q_OS_MAC + return false; +#endif // !Q_OS_MAC + }, + .restartRequired = true, +}); + } // namespace. const char kOptionNewWindowsSizeAsFirst[] = "new-windows-size-as-first"; +const char kOptionDisableTouchbar[] = "touchbar-disabled"; const QImage &Logo() { static const auto result = QImage(u":/gui/art/logo_256.png"_q); diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index 85d495e7e3bfa8..d0b5fedcef2142 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -55,6 +55,7 @@ struct CounterLayerArgs { }; extern const char kOptionNewWindowsSizeAsFirst[]; +extern const char kOptionDisableTouchbar[]; [[nodiscard]] QImage GenerateCounterLayer(CounterLayerArgs &&args); [[nodiscard]] QImage WithSmallCounter(QImage image, CounterLayerArgs &&args); From c9f7da6e821e04b525fe8421f33bf6462579a7aa Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 3 Sep 2024 14:54:23 +0300 Subject: [PATCH 10/41] Added ability to paint icons in center of QRectF. --- Telegram/SourceFiles/boxes/edit_privacy_box.cpp | 2 +- Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp | 5 +++-- Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp | 2 +- Telegram/SourceFiles/history/view/history_view_message.cpp | 6 +++--- .../info/statistics/info_statistics_list_controllers.cpp | 2 +- .../SourceFiles/settings/business/settings_chat_links.cpp | 3 ++- Telegram/lib_ui | 2 +- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp index c8536d944e2256..6352c5b51d3a42 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp @@ -195,7 +195,7 @@ PaintRoundImageCallback PremiumsRow::generatePaintUserpicCallback( const auto radius = size * Ui::ForumUserpicRadiusMultiplier(); p.drawRoundedRect(x, y, size, size, radius, radius); } - st::settingsPrivacyPremium.paintInCenter(p, { x, y, size, size }); + st::settingsPrivacyPremium.paintInCenter(p, QRect(x, y, size, size)); }; } diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp index 13f5b146d4538c..7dc09ae3a02801 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp @@ -31,6 +31,7 @@ For license and copyright information please follow this link: #include "ui/wrap/vertical_layout.h" #include "ui/wrap/slide_wrap.h" #include "ui/painter.h" +#include "ui/rect.h" #include "ui/vertical_list.h" #include "window/window_session_controller.h" #include "styles/style_info.h" @@ -965,9 +966,9 @@ void LinksController::rowPaintIcon( p.setBrush(*bg); { auto hq = PainterHighQualityEnabler(p); - p.drawEllipse(QRect(0, 0, inner, inner)); + p.drawEllipse(Rect(Size(inner))); } - st::inviteLinkIcon.paintInCenter(p, { 0, 0, inner, inner }); + st::inviteLinkIcon.paintInCenter(p, Rect(Size(inner))); } p.drawImage(x + skip, y + skip, icon); } diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp index 7cdc29224688b1..86d8e3595651a0 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp @@ -734,7 +734,7 @@ void LinksController::rowPaintIcon( } else { (color == Color::Revoked ? st::inviteLinkRevokedIcon - : st::inviteLinkIcon).paintInCenter(p, { 0, 0, inner, inner }); + : st::inviteLinkIcon).paintInCenter(p, Rect(Size(inner))); } } p.drawImage(x + skip, y + skip, icon); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 074cc41eb3cff3..146f8689452fc2 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -3831,10 +3831,10 @@ void Message::drawRightAction( } else if (_rightAction->second) { st->historyFastCloseIcon().paintInCenter( p, - { left, top, size->width(), size->width() }); + QRect(left, top, size->width(), size->width())); st->historyFastMoreIcon().paintInCenter( p, - { left, size->width() + top, size->width(), size->width() }); + QRect(left, size->width() + top, size->width(), size->width())); } else { const auto &icon = data()->isSponsored() ? st->historyFastCloseIcon() @@ -3843,7 +3843,7 @@ void Message::drawRightAction( && this->context() != Context::SavedSublist) ? st->historyFastShareIcon() : st->historyGoToOriginalIcon(); - icon.paintInCenter(p, { left, top, size->width(), size->height() }); + icon.paintInCenter(p, Rect(left, top, *size)); } } diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp index e9171dd186b8f1..050ff4a97186be 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp @@ -536,7 +536,7 @@ PaintRoundImageCallback BoostRow::generatePaintUserpicCallback(bool force) { ? st::boostsListUnclaimedIcon : st::boostsListUnknownIcon).paintInCenter( p, - { x, y, size, size }); + Rect(x, y, Size(size))); }; } diff --git a/Telegram/SourceFiles/settings/business/settings_chat_links.cpp b/Telegram/SourceFiles/settings/business/settings_chat_links.cpp index 796701b2252a74..e984b9b23381bd 100644 --- a/Telegram/SourceFiles/settings/business/settings_chat_links.cpp +++ b/Telegram/SourceFiles/settings/business/settings_chat_links.cpp @@ -37,6 +37,7 @@ For license and copyright information please follow this link: #include "ui/wrap/slide_wrap.h" #include "ui/wrap/vertical_layout.h" #include "ui/painter.h" +#include "ui/rect.h" #include "ui/vertical_list.h" #include "window/window_session_controller.h" #include "styles/style_chat.h" @@ -688,7 +689,7 @@ void LinksController::rowPaintIcon( auto rect = QRect(0, 0, inner, inner); p.drawEllipse(rect); } - st::inviteLinkIcon.paintInCenter(p, { 0, 0, inner, inner }); + st::inviteLinkIcon.paintInCenter(p, Rect(Size(inner))); } p.drawImage(x + skip, y + skip, _icon); } diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 1508241e092dc2..9d2c1836ebdf48 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 1508241e092dc240ee984f2b15da972c2c5fcae1 +Subproject commit 9d2c1836ebdf48f37d1f461b19e2d4cbb60b1c2f From 7f70ee122779634c1a53b03a3b2f296b7dc71c54 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 2 Sep 2024 20:14:33 +0300 Subject: [PATCH 11/41] Added initial ability to reply with left swipe. --- .../history/history_inner_widget.cpp | 81 ++++++++- .../history/history_inner_widget.h | 3 + .../history/history_view_swipe.cpp | 164 ++++++++++++++++++ .../SourceFiles/history/history_view_swipe.h | 30 ++++ .../history/history_view_swipe_data.h | 19 ++ .../history/view/history_view_element.cpp | 7 + .../history/view/history_view_message.cpp | 41 +++++ .../history_view_reactions_button.cpp | 4 + Telegram/SourceFiles/ui/chat/chat_style.h | 2 + Telegram/cmake/td_ui.cmake | 3 + Telegram/lib_base | 2 +- 11 files changed, 347 insertions(+), 9 deletions(-) create mode 100644 Telegram/SourceFiles/history/history_view_swipe.cpp create mode 100644 Telegram/SourceFiles/history/history_view_swipe.h create mode 100644 Telegram/SourceFiles/history/history_view_swipe_data.h diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index d682fc81c2a344..370a70b0ea384e 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -27,6 +27,7 @@ For license and copyright information please follow this link: #include "history/view/history_view_emoji_interactions.h" #include "history/history_item_components.h" #include "history/history_item_text.h" +#include "history/history_view_swipe.h" #include "payments/payments_reaction_process.h" #include "ui/widgets/menu/menu_add_action_callback_factory.h" #include "ui/widgets/menu/menu_multiline_action.h" @@ -123,6 +124,15 @@ int BinarySearchBlocksOrItems(const T &list, int edge) { return start; } +[[nodiscard]] bool CanSendReply(not_null item) { + const auto peer = item->history()->peer; + const auto topic = item->topic(); + return topic + ? Data::CanSendAnything(topic) + : (Data::CanSendAnything(peer) + && (!peer->isChannel() || peer->asChannel()->amIn())); +} + void FillSponsoredMessagesMenu( not_null controller, FullMsgId itemId, @@ -373,6 +383,59 @@ HistoryInner::HistoryInner( _migrated->delegateMixin()->setCurrent(this); _migrated->translateTo(_history->translatedTo()); } + HistoryView::SetupSwipeHandler(this, _scroll, [=]( + HistoryView::ChatPaintGestureHorizontalData data) { + _gestureHorizontal = data; + update(); + }, [=, show = controller->uiShow()](int cursorTop) { + auto result = HistoryView::SwipeHandlerFinishData(); + if (inSelectionMode()) { + return result; + } + enumerateItems([&]( + not_null view, + int itemtop, + int itembottom) { + if ((cursorTop < itemtop) + || (cursorTop > itembottom) + || !view->data()->isRegular() + || view->data()->isService()) { + return true; + } + const auto item = view->data(); + const auto canSendReply = CanSendReply(item); + const auto canReply = (canSendReply || item->allowsForward()); + if (!canReply) { + return true; + } + result.msgBareId = item->fullId().msg.bare; + result.callback = [=, itemId = item->fullId()] { + const auto still = show->session().data().message(itemId); + const auto selected = selectedQuote(still); + const auto replyToItemId = (selected.item + ? selected.item + : still)->fullId(); + if (canSendReply) { + _widget->replyToMessage({ + .messageId = replyToItemId, + .quote = selected.text, + .quoteOffset = selected.offset, + }); + if (!selected.text.empty()) { + _widget->clearSelected(); + } + } else { + HistoryView::Controls::ShowReplyToChatBox(show, { + .messageId = replyToItemId, + .quote = selected.text, + .quoteOffset = selected.offset, + }); + } + }; + return false; + }); + return result; + }); Window::ChatThemeValueFromPeer( controller, @@ -944,6 +1007,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { auto clip = e->rect(); auto context = preparePaintContext(clip); + context.gestureHorizontal = _gestureHorizontal; context.highlightPathCache = &_highlightPathCache; _pathGradient->startFrame( 0, @@ -1157,6 +1221,11 @@ void HistoryInner::paintEvent(QPaintEvent *e) { // paint the userpic if it intersects the painted rect if (userpicTop + st::msgPhotoSize > clip.top()) { const auto item = view->data(); + const auto hasTranslation = _gestureHorizontal.ratio + && (_gestureHorizontal.msgBareId == item->fullId().msg.bare); + if (hasTranslation) { + p.translate(_gestureHorizontal.translation, 0); + } if (const auto from = item->displayFrom()) { Dialogs::Ui::PaintUserpic( p, @@ -1192,6 +1261,9 @@ void HistoryInner::paintEvent(QPaintEvent *e) { } else { Unexpected("Corrupt forwarded information in message."); } + if (hasTranslation) { + p.translate(-_gestureHorizontal.translation, 0); + } } return true; }); @@ -2461,14 +2533,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (!item || !item->isRegular()) { return; } - const auto canSendReply = [&] { - const auto peer = item->history()->peer; - const auto topic = item->topic(); - return topic - ? Data::CanSendAnything(topic) - : (Data::CanSendAnything(peer) - && (!peer->isChannel() || peer->asChannel()->amIn())); - }(); + const auto canSendReply = CanSendReply(item); const auto canReply = canSendReply || item->allowsForward(); if (canReply) { const auto selected = selectedQuote(item); diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 5a11b2944a48d9..2507a09214358b 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -13,6 +13,7 @@ For license and copyright information please follow this link: #include "ui/dragging_scroll_manager.h" #include "ui/widgets/tooltip.h" #include "ui/widgets/scroll_area.h" +#include "history/history_view_swipe_data.h" #include "history/view/history_view_top_bar_widget.h" #include @@ -526,6 +527,8 @@ class HistoryInner crl::time _touchTime = 0; base::Timer _touchScrollTimer; + HistoryView::ChatPaintGestureHorizontalData _gestureHorizontal; + // _menu must be destroyed before _whoReactedMenuLifetime. rpl::lifetime _whoReactedMenuLifetime; base::unique_qptr _menu; diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp new file mode 100644 index 00000000000000..7a254c51a38b47 --- /dev/null +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -0,0 +1,164 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "history/history_view_swipe.h" + +#include "base/event_filter.h" +#include "base/platform/base_platform_haptic.h" +#include "history/history_view_swipe_data.h" +#include "ui/chat/chat_style.h" +#include "ui/ui_utility.h" +#include "ui/widgets/scroll_area.h" + +#include + +namespace HistoryView { + +void SetupSwipeHandler( + not_null widget, + not_null scroll, + Fn update, + Fn generateFinishByTop) { + constexpr auto kThresholdWidth = 50; + const auto threshold = style::ConvertFloatScale(kThresholdWidth); + struct State { + base::unique_qptr filter; + Ui::Animations::Simple animationEnd; + SwipeHandlerFinishData finishByTopData; + std::optional orientation; + QPointF startAt; + QPointF lastAt; + int cursorTop = 0; + bool reached = false; + + rpl::lifetime lifetime; + }; + const auto state = widget->lifetime().make_state(); + const auto updateRatio = [=](float64 ratio) { + update({ + .ratio = std::clamp(ratio, 0., 1.), + .translation = (-std::clamp(ratio, 0., 1.5) * threshold), + .msgBareId = state->finishByTopData.msgBareId, + .cursorTop = state->cursorTop, + }); + }; + const auto setOrientation = [=](const std::optional &o) { + state->orientation = o; + const auto isHorizontal = o.value_or(Qt::Vertical) == Qt::Horizontal; + scroll->viewport()->setAttribute( + Qt::WA_AcceptTouchEvents, + !isHorizontal); + scroll->disableScroll(isHorizontal); + }; + const auto processEnd = [=](QTouchEvent *t) { + if (state->orientation) { + if ((*state->orientation) == Qt::Horizontal) { + if (t && t->touchPoints().size() > 0) { + state->lastAt = t->touchPoints().at(0).pos(); + } + const auto delta = state->startAt - state->lastAt; + const auto ratio = delta.x() / threshold; + if ((ratio >= 1) && state->finishByTopData.callback) { + Ui::PostponeCall( + widget, + state->finishByTopData.callback); + } + state->animationEnd.stop(); + state->animationEnd.start( + updateRatio, + ratio, + 0., + st::slideWrapDuration); + } + } + setOrientation(std::nullopt); + state->startAt = QPointF(); + state->reached = false; + }; + scroll->scrolls() | rpl::start_with_next([=] { + processEnd(nullptr); + }, state->lifetime); + const auto filter = [=](not_null e) { + if (e->type() == QEvent::Leave && state->orientation) { + processEnd(nullptr); + } + if (e->type() == QEvent::MouseMove && state->orientation) { + const auto m = static_cast(e.get()); + if (std::abs(m->pos().y() - state->cursorTop) + > QApplication::startDragDistance()) { + processEnd(nullptr); + } + } + if (e->type() == QEvent::TouchBegin + || e->type() == QEvent::TouchUpdate + || e->type() == QEvent::TouchEnd + || e->type() == QEvent::TouchCancel) { + const auto t = static_cast(e.get()); + const auto &touches = t->touchPoints(); + const auto anyReleased = (touches.size() == 2) + ? ((touches.at(0).state() & Qt::TouchPointReleased) + + (touches.at(1).state() & Qt::TouchPointReleased)) + : (touches.size() == 1) + ? (touches.at(0).state() & Qt::TouchPointReleased) + : 0; + if (touches.size() == 2) { + if ((e->type() == QEvent::TouchBegin) + || (e->type() == QEvent::TouchUpdate)) { + if (state->startAt.isNull()) { + state->startAt = touches.at(0).pos(); + state->cursorTop = widget->mapFromGlobal( + QCursor::pos()).y(); + state->finishByTopData = generateFinishByTop( + state->cursorTop); + if (!state->finishByTopData.callback) { + setOrientation(Qt::Vertical); + } + } else if (state->orientation) { + if ((*state->orientation) == Qt::Horizontal) { + state->lastAt = touches.at(0).pos(); + const auto delta = state->startAt - state->lastAt; + const auto ratio = delta.x() / threshold; + updateRatio(ratio); + constexpr auto kResetReachedOn = 0.95; + if (!state->reached && ratio >= 1.) { + state->reached = true; + base::Platform::Haptic(); + } else if (state->reached + && ratio < kResetReachedOn) { + state->reached = false; + } + } + } else { + state->lastAt = touches.at(0).pos(); + const auto delta = state->startAt - state->lastAt; + const auto diffXtoY = std::abs(delta.x()) + - std::abs(delta.y()); + if (diffXtoY > 0) { + setOrientation(Qt::Horizontal); + } else if (diffXtoY < 0) { + setOrientation(Qt::Vertical); + } else { + setOrientation(std::nullopt); + } + } + } + } + if ((e->type() == QEvent::TouchEnd) + || touches.empty() + || anyReleased + || (touches.size() > 2)) { + processEnd(t); + } + return base::EventFilterResult::Cancel; + } + return base::EventFilterResult::Continue; + }; + state->filter = base::make_unique_q( + base::install_event_filter(widget, filter)); +} + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/history_view_swipe.h b/Telegram/SourceFiles/history/history_view_swipe.h new file mode 100644 index 00000000000000..e7fb2ea4a53dec --- /dev/null +++ b/Telegram/SourceFiles/history/history_view_swipe.h @@ -0,0 +1,30 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +namespace Ui { +class RpWidget; +class ScrollArea; +} // namespace Ui + +namespace HistoryView { + +struct ChatPaintGestureHorizontalData; + +struct SwipeHandlerFinishData { + Fn callback; + int64 msgBareId = 0; +}; + +void SetupSwipeHandler( + not_null widget, + not_null scroll, + Fn update, + Fn generateFinishByTop); + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/history_view_swipe_data.h b/Telegram/SourceFiles/history/history_view_swipe_data.h new file mode 100644 index 00000000000000..c42b146b883076 --- /dev/null +++ b/Telegram/SourceFiles/history/history_view_swipe_data.h @@ -0,0 +1,19 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +namespace HistoryView { + +struct ChatPaintGestureHorizontalData { + float64 ratio = 0.; + float64 translation = 0.; + int64 msgBareId = 0; + int cursorTop = 0; +}; + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index d36c32a2c5d319..883b51a5aa5439 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -315,6 +315,10 @@ void UnreadBar::paint( int y, int w, bool chatWide) const { + const auto previousTranslation = p.transform().dx(); + if (previousTranslation != 0) { + p.translate(-previousTranslation, 0); + } const auto st = context.st; const auto bottom = y + height(); y += marginTop(); @@ -350,6 +354,9 @@ void UnreadBar::paint( (w - width) / 2, y + (skip / 2) + st::historyUnreadBarFont->ascent, text); + if (previousTranslation != 0) { + p.translate(previousTranslation, 0); + } } void DateBadge::init(const QString &date) { diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 146f8689452fc2..b5b0dea665d12b 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1091,6 +1091,12 @@ void Message::draw(Painter &p, const PaintContext &context) const { const auto item = data(); const auto media = this->media(); + const auto hasGesture = context.gestureHorizontal.ratio + && (context.gestureHorizontal.msgBareId == item->fullId().msg.bare); + if (hasGesture) { + p.translate(context.gestureHorizontal.translation, 0); + } + if (item->hasUnrequestedFactcheck()) { item->history()->session().factchecks().requestFor(item); } @@ -1481,6 +1487,41 @@ void Message::draw(Painter &p, const PaintContext &context) const { } } } + if (hasGesture) { + p.translate(-context.gestureHorizontal.translation, 0); + + constexpr auto kShiftRatio = 1.5; + const auto size = st::historyFastShareSize; + const auto rect = QRect( + width() - (size * kShiftRatio) * context.gestureHorizontal.ratio, + g.y() + (g.height() - size) / 2, + size, + size); + const auto center = rect::center(rect); + const auto spanAngle = -context.gestureHorizontal.ratio + * arc::kFullLength; + const auto strokeWidth = style::ConvertFloatScale(2.); + auto pen = QPen(context.st->msgServiceBg()); + pen.setWidthF(strokeWidth); + const auto arcRect = rect - Margins(strokeWidth); + p.save(); + { + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush(context.st->msgServiceBg()); + p.setOpacity(context.gestureHorizontal.ratio); + p.drawEllipse(rect); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + p.drawArc(arcRect, arc::kQuarterLength, spanAngle); + p.drawArc(arcRect, arc::kQuarterLength, spanAngle); + p.translate(center); + p.scale(-1., 1.); + p.translate(-center); + context.st->historyFastShareIcon().paintInCenter(p, rect); + } + p.restore(); + } } void Message::paintCommentsButton( diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp index 4464e9546cd748..9f2759f36ba952 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp @@ -488,6 +488,10 @@ void Manager::paint(QPainter &p, const PaintContext &context) { paintButton(p, context, button.get()); } if (const auto current = _button.get()) { + if (context.gestureHorizontal.ratio) { + current->applyState(ButtonState::Hidden); + _buttonHiding.push_back(std::move(_button)); + } paintButton(p, context, current); } diff --git a/Telegram/SourceFiles/ui/chat/chat_style.h b/Telegram/SourceFiles/ui/chat/chat_style.h index a00fe941ab13ea..b66cf814bcd472 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.h +++ b/Telegram/SourceFiles/ui/chat/chat_style.h @@ -11,6 +11,7 @@ For license and copyright information please follow this link: #include "ui/chat/message_bubble.h" #include "ui/chat/chat_style_radius.h" #include "ui/style/style_core_palette.h" +#include "history/history_view_swipe_data.h" #include "layout/layout_selection.h" #include "styles/style_basic.h" @@ -164,6 +165,7 @@ struct ChatPaintContext { QPainterPath *highlightPathCache = nullptr; mutable QRect highlightInterpolateTo; crl::time now = 0; + HistoryView::ChatPaintGestureHorizontalData gestureHorizontal; void translate(int x, int y) { viewport.translate(x, y); diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index 00871161df82e0..2eef94d8e60be2 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -127,6 +127,9 @@ PRIVATE history/admin_log/history_admin_log_filter_value.h history/history_view_top_toast.cpp history/history_view_top_toast.h + history/history_view_swipe.cpp + history/history_view_swipe.h + history/history_view_swipe_data.h history/view/controls/history_view_characters_limit.cpp history/view/controls/history_view_characters_limit.h history/view/controls/history_view_voice_record_button.cpp diff --git a/Telegram/lib_base b/Telegram/lib_base index 601c20431cc3f9..547e7f2914d9b5 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit 601c20431cc3f91de01e1b13a033e0a41cd36353 +Subproject commit 547e7f2914d9b5548dd17e70a3a7bf5d6606afc3 From 6129e5a1cf5edcdf867fc807229fa575240c4c13 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 3 Sep 2024 10:19:41 +0300 Subject: [PATCH 12/41] Added bounce animation on finish of replying with left swipe. --- .../history/history_view_swipe.cpp | 12 +++++ .../history/history_view_swipe_data.h | 1 + .../history/view/history_view_message.cpp | 53 +++++++++++++++---- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index 7a254c51a38b47..a3bef4bd339d46 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -27,6 +27,7 @@ void SetupSwipeHandler( const auto threshold = style::ConvertFloatScale(kThresholdWidth); struct State { base::unique_qptr filter; + Ui::Animations::Simple animationReach; Ui::Animations::Simple animationEnd; SwipeHandlerFinishData finishByTopData; std::optional orientation; @@ -41,6 +42,7 @@ void SetupSwipeHandler( const auto updateRatio = [=](float64 ratio) { update({ .ratio = std::clamp(ratio, 0., 1.), + .reachRatio = state->animationReach.value(0.), .translation = (-std::clamp(ratio, 0., 1.5) * threshold), .msgBareId = state->finishByTopData.msgBareId, .cursorTop = state->cursorTop, @@ -82,6 +84,9 @@ void SetupSwipeHandler( scroll->scrolls() | rpl::start_with_next([=] { processEnd(nullptr); }, state->lifetime); + const auto animationReachCallback = [=] { + updateRatio((state->startAt - state->lastAt).x() / threshold); + }; const auto filter = [=](not_null e) { if (e->type() == QEvent::Leave && state->orientation) { processEnd(nullptr); @@ -124,8 +129,15 @@ void SetupSwipeHandler( const auto ratio = delta.x() / threshold; updateRatio(ratio); constexpr auto kResetReachedOn = 0.95; + constexpr auto kBounceDuration = crl::time(500); if (!state->reached && ratio >= 1.) { state->reached = true; + state->animationReach.stop(); + state->animationReach.start( + animationReachCallback, + 0., + 1., + kBounceDuration); base::Platform::Haptic(); } else if (state->reached && ratio < kResetReachedOn) { diff --git a/Telegram/SourceFiles/history/history_view_swipe_data.h b/Telegram/SourceFiles/history/history_view_swipe_data.h index c42b146b883076..a08ef8e2c76909 100644 --- a/Telegram/SourceFiles/history/history_view_swipe_data.h +++ b/Telegram/SourceFiles/history/history_view_swipe_data.h @@ -11,6 +11,7 @@ namespace HistoryView { struct ChatPaintGestureHorizontalData { float64 ratio = 0.; + float64 reachRatio = 0.; float64 translation = 0.; int64 msgBareId = 0; int cursorTop = 0; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index b5b0dea665d12b..fb6a5175b5a179 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -40,6 +40,7 @@ For license and copyright information please follow this link: #include "payments/payments_reaction_process.h" // TryAddingPaidReaction. #include "ui/text/text_options.h" #include "ui/painter.h" +#include "window/themes/window_theme.h" // IsNightMode. #include "window/window_session_controller.h" #include "apiwrap.h" #include "styles/style_chat.h" @@ -1491,18 +1492,31 @@ void Message::draw(Painter &p, const PaintContext &context) const { p.translate(-context.gestureHorizontal.translation, 0); constexpr auto kShiftRatio = 1.5; + constexpr auto kBouncePart = 0.25; + constexpr auto kStrokeWidth = 2.; + constexpr auto kWaveWidth = 10.; + const auto reachRatio = context.gestureHorizontal.reachRatio; const auto size = st::historyFastShareSize; - const auto rect = QRect( + const auto rect = QRectF( width() - (size * kShiftRatio) * context.gestureHorizontal.ratio, g.y() + (g.height() - size) / 2, size, size); const auto center = rect::center(rect); - const auto spanAngle = -context.gestureHorizontal.ratio + const auto spanAngle = context.gestureHorizontal.ratio * arc::kFullLength; - const auto strokeWidth = style::ConvertFloatScale(2.); - auto pen = QPen(context.st->msgServiceBg()); - pen.setWidthF(strokeWidth); + const auto strokeWidth = style::ConvertFloatScale(kStrokeWidth); + + const auto reachScale = std::clamp( + (reachRatio > kBouncePart) + ? (kBouncePart * 2 - reachRatio) + : reachRatio, + 0., + 1.); + auto pen = Window::Theme::IsNightMode() + ? QPen(anim::with_alpha(context.st->msgServiceFg()->c, 0.3)) + : QPen(context.st->msgServiceBg()); + pen.setWidthF(strokeWidth - (1. * (reachScale / kBouncePart))); const auto arcRect = rect - Margins(strokeWidth); p.save(); { @@ -1510,15 +1524,34 @@ void Message::draw(Painter &p, const PaintContext &context) const { p.setPen(Qt::NoPen); p.setBrush(context.st->msgServiceBg()); p.setOpacity(context.gestureHorizontal.ratio); + p.translate(center); + if (reachScale) { + p.scale(-(1. + 1. * reachScale), (1. + 1. * reachScale)); + } else { + p.scale(-1., 1.); + } + p.translate(-center); + // All the next draws are mirrored. p.drawEllipse(rect); + context.st->historyFastShareIcon().paintInCenter( + p, + QRect( + base::SafeRound(rect.x()), + base::SafeRound(rect.y()), + base::SafeRound(rect.width()), + base::SafeRound(rect.height()))); p.setPen(pen); p.setBrush(Qt::NoBrush); p.drawArc(arcRect, arc::kQuarterLength, spanAngle); - p.drawArc(arcRect, arc::kQuarterLength, spanAngle); - p.translate(center); - p.scale(-1., 1.); - p.translate(-center); - context.st->historyFastShareIcon().paintInCenter(p, rect); + // p.drawArc(arcRect, arc::kQuarterLength, spanAngle); + if (reachRatio) { + const auto w = style::ConvertFloatScale(kWaveWidth); + p.setOpacity(context.gestureHorizontal.ratio - reachRatio); + p.drawArc( + arcRect + Margins(reachRatio * reachRatio * w), + arc::kQuarterLength, + spanAngle); + } } p.restore(); } From 3d2af9db8e53aa946bdb116c0aba5c2d1ab366b8 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 3 Sep 2024 11:39:52 +0300 Subject: [PATCH 13/41] Improved distance of reply icon on left swipe. --- Telegram/SourceFiles/history/history_view_swipe.cpp | 2 +- .../SourceFiles/history/view/history_view_message.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index a3bef4bd339d46..d83c3cda9cbbbd 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -41,7 +41,7 @@ void SetupSwipeHandler( const auto state = widget->lifetime().make_state(); const auto updateRatio = [=](float64 ratio) { update({ - .ratio = std::clamp(ratio, 0., 1.), + .ratio = std::clamp(ratio, 0., 1.5), .reachRatio = state->animationReach.value(0.), .translation = (-std::clamp(ratio, 0., 1.5) * threshold), .msgBareId = state->finishByTopData.msgBareId, diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index fb6a5175b5a179..86cdb4fcb06a8a 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1495,6 +1495,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { constexpr auto kBouncePart = 0.25; constexpr auto kStrokeWidth = 2.; constexpr auto kWaveWidth = 10.; + const auto ratio = std::min(context.gestureHorizontal.ratio, 1.); const auto reachRatio = context.gestureHorizontal.reachRatio; const auto size = st::historyFastShareSize; const auto rect = QRectF( @@ -1503,8 +1504,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { size, size); const auto center = rect::center(rect); - const auto spanAngle = context.gestureHorizontal.ratio - * arc::kFullLength; + const auto spanAngle = ratio * arc::kFullLength; const auto strokeWidth = style::ConvertFloatScale(kStrokeWidth); const auto reachScale = std::clamp( @@ -1523,7 +1523,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { auto hq = PainterHighQualityEnabler(p); p.setPen(Qt::NoPen); p.setBrush(context.st->msgServiceBg()); - p.setOpacity(context.gestureHorizontal.ratio); + p.setOpacity(ratio); p.translate(center); if (reachScale) { p.scale(-(1. + 1. * reachScale), (1. + 1. * reachScale)); @@ -1546,7 +1546,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { // p.drawArc(arcRect, arc::kQuarterLength, spanAngle); if (reachRatio) { const auto w = style::ConvertFloatScale(kWaveWidth); - p.setOpacity(context.gestureHorizontal.ratio - reachRatio); + p.setOpacity(ratio - reachRatio); p.drawArc( arcRect + Margins(reachRatio * reachRatio * w), arc::kQuarterLength, From fb1b845211b7eae82143faf4ad25c3838fb956dd Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 3 Sep 2024 13:32:17 +0300 Subject: [PATCH 14/41] Improved process of message repaint on swipe to reply. --- Telegram/SourceFiles/history/history_inner_widget.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 370a70b0ea384e..7f35315b8131ec 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -383,10 +383,15 @@ HistoryInner::HistoryInner( _migrated->delegateMixin()->setCurrent(this); _migrated->translateTo(_history->translatedTo()); } - HistoryView::SetupSwipeHandler(this, _scroll, [=]( + HistoryView::SetupSwipeHandler(this, _scroll, [=, history = _history]( HistoryView::ChatPaintGestureHorizontalData data) { _gestureHorizontal = data; - update(); + const auto item = history->peer->owner().message( + history->peer->id, + MsgId{ data.msgBareId }); + if (item) { + repaintItem(item); + } }, [=, show = controller->uiShow()](int cursorTop) { auto result = HistoryView::SwipeHandlerFinishData(); if (inSelectionMode()) { From 2aa58499972783bc9a004c97cd1f01ae41341f15 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 3 Sep 2024 14:18:17 +0300 Subject: [PATCH 15/41] Improved horizontal animation for reply icon on left swipe. --- .../history/view/history_view_message.cpp | 16 ++++++++-------- Telegram/SourceFiles/ui/chat/chat.style | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 86cdb4fcb06a8a..669ad90fa55630 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1495,11 +1495,17 @@ void Message::draw(Painter &p, const PaintContext &context) const { constexpr auto kBouncePart = 0.25; constexpr auto kStrokeWidth = 2.; constexpr auto kWaveWidth = 10.; + const auto isLeftSize = (!context.outbg) + || delegate()->elementIsChatWide(); const auto ratio = std::min(context.gestureHorizontal.ratio, 1.); const auto reachRatio = context.gestureHorizontal.reachRatio; const auto size = st::historyFastShareSize; + const auto outerWidth = st::historySwipeIconSkip + + (isLeftSize ? rect::right(g) : width()); const auto rect = QRectF( - width() - (size * kShiftRatio) * context.gestureHorizontal.ratio, + outerWidth + - (size * kShiftRatio * context.gestureHorizontal.ratio) + - (st::historySwipeIconSkip * ratio * (isLeftSize ? .7 : 1.)), g.y() + (g.height() - size) / 2, size, size); @@ -1533,13 +1539,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { p.translate(-center); // All the next draws are mirrored. p.drawEllipse(rect); - context.st->historyFastShareIcon().paintInCenter( - p, - QRect( - base::SafeRound(rect.x()), - base::SafeRound(rect.y()), - base::SafeRound(rect.width()), - base::SafeRound(rect.height()))); + context.st->historyFastShareIcon().paintInCenter(p, rect); p.setPen(pen); p.setBrush(Qt::NoBrush); p.drawArc(arcRect, arc::kQuarterLength, spanAngle); diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 27b9e36c1b2219..42e580fa6c60b6 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -570,6 +570,8 @@ historyFastTranscribeLockPos: point(18px, 13px); historyFastTranscribeLockOverlayPos: point(21px, 13px); historyFastTranscribeLockOverlaySize: size(6px, 10px); +historySwipeIconSkip: 80px; + historySavedFont: font(semibold 14px); historyGroupWidthMax: maxMediaSize; From 300f35e78ff11b8ec6542b5b4bec832760741cd6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 3 Sep 2024 17:39:19 +0400 Subject: [PATCH 16/41] Implement both touch and wheel swipe-to-reply. --- .../history/history_view_swipe.cpp | 235 ++++++++++-------- 1 file changed, 137 insertions(+), 98 deletions(-) diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index d83c3cda9cbbbd..c6f297dcf74660 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -7,11 +7,14 @@ For license and copyright information please follow this link: */ #include "history/history_view_swipe.h" -#include "base/event_filter.h" #include "base/platform/base_platform_haptic.h" +#include "base/platform/base_platform_info.h" +#include "base/qt/qt_common_adapters.h" +#include "base/event_filter.h" #include "history/history_view_swipe_data.h" #include "ui/chat/chat_style.h" #include "ui/ui_utility.h" +#include "ui/widgets/elastic_scroll.h" #include "ui/widgets/scroll_area.h" #include @@ -32,9 +35,11 @@ void SetupSwipeHandler( SwipeHandlerFinishData finishByTopData; std::optional orientation; QPointF startAt; - QPointF lastAt; + QPointF delta; int cursorTop = 0; + bool started = false; bool reached = false; + bool touch = false; rpl::lifetime lifetime; }; @@ -48,124 +53,158 @@ void SetupSwipeHandler( .cursorTop = state->cursorTop, }); }; - const auto setOrientation = [=](const std::optional &o) { + const auto setOrientation = [=](std::optional o) { state->orientation = o; - const auto isHorizontal = o.value_or(Qt::Vertical) == Qt::Horizontal; + const auto isHorizontal = (o == Qt::Horizontal); scroll->viewport()->setAttribute( Qt::WA_AcceptTouchEvents, !isHorizontal); scroll->disableScroll(isHorizontal); }; - const auto processEnd = [=](QTouchEvent *t) { - if (state->orientation) { - if ((*state->orientation) == Qt::Horizontal) { - if (t && t->touchPoints().size() > 0) { - state->lastAt = t->touchPoints().at(0).pos(); - } - const auto delta = state->startAt - state->lastAt; - const auto ratio = delta.x() / threshold; - if ((ratio >= 1) && state->finishByTopData.callback) { - Ui::PostponeCall( - widget, - state->finishByTopData.callback); - } - state->animationEnd.stop(); - state->animationEnd.start( - updateRatio, - ratio, - 0., - st::slideWrapDuration); + const auto processEnd = [=](std::optional delta = {}) { + if (state->orientation == Qt::Horizontal) { + const auto ratio = delta.value_or(state->delta).x() / threshold; + if ((ratio >= 1) && state->finishByTopData.callback) { + Ui::PostponeCall( + widget, + state->finishByTopData.callback); } + state->animationReach.stop(); + state->animationEnd.stop(); + state->animationEnd.start( + updateRatio, + ratio, + 0., + st::slideWrapDuration); } setOrientation(std::nullopt); - state->startAt = QPointF(); + state->started = false; state->reached = false; }; scroll->scrolls() | rpl::start_with_next([=] { - processEnd(nullptr); + processEnd(); }, state->lifetime); const auto animationReachCallback = [=] { - updateRatio((state->startAt - state->lastAt).x() / threshold); + updateRatio(state->delta.x() / threshold); }; - const auto filter = [=](not_null e) { - if (e->type() == QEvent::Leave && state->orientation) { - processEnd(nullptr); + struct UpdateArgs { + QPointF position; + QPointF delta; + bool touch = false; + }; + const auto updateWith = [=](UpdateArgs &&args) { + if (!state->started || state->touch != args.touch) { + state->started = true; + state->touch = args.touch; + state->startAt = args.position; + state->delta = QPointF(); + state->cursorTop = widget->mapFromGlobal( + QCursor::pos()).y(); + state->finishByTopData = generateFinishByTop( + state->cursorTop); + if (!state->finishByTopData.callback) { + setOrientation(Qt::Vertical); + } + } else if (!state->orientation) { + state->delta = args.delta; + const auto diffXtoY = std::abs(args.delta.x()) + - std::abs(args.delta.y()); + if (diffXtoY > 0) { + setOrientation(Qt::Horizontal); + } else if (diffXtoY < 0) { + setOrientation(Qt::Vertical); + } else { + setOrientation(std::nullopt); + } + } else if (*state->orientation == Qt::Horizontal) { + state->delta = args.delta; + const auto ratio = args.delta.x() / threshold; + updateRatio(ratio); + constexpr auto kResetReachedOn = 0.95; + constexpr auto kBounceDuration = crl::time(500); + if (!state->reached && ratio >= 1.) { + state->reached = true; + state->animationReach.stop(); + state->animationReach.start( + animationReachCallback, + 0., + 1., + kBounceDuration); + base::Platform::Haptic(); + } else if (state->reached + && ratio < kResetReachedOn) { + state->reached = false; + } } - if (e->type() == QEvent::MouseMove && state->orientation) { - const auto m = static_cast(e.get()); - if (std::abs(m->pos().y() - state->cursorTop) + }; + const auto filter = [=](not_null e) { + const auto type = e->type(); + switch (type) { + case QEvent::Leave: + if (state->orientation) { + processEnd(); + } + break; + case QEvent::MouseMove: + if (state->orientation) { + const auto m = static_cast(e.get()); + if (std::abs(m->pos().y() - state->cursorTop) > QApplication::startDragDistance()) { - processEnd(nullptr); + processEnd(); + } } - } - if (e->type() == QEvent::TouchBegin - || e->type() == QEvent::TouchUpdate - || e->type() == QEvent::TouchEnd - || e->type() == QEvent::TouchCancel) { + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::TouchCancel: { const auto t = static_cast(e.get()); + const auto touchscreen = t->device() + && (t->device()->type() != base::TouchDevice::TouchScreen); + if (!Platform::IsMac() && !touchscreen) { + break; + } const auto &touches = t->touchPoints(); - const auto anyReleased = (touches.size() == 2) - ? ((touches.at(0).state() & Qt::TouchPointReleased) - + (touches.at(1).state() & Qt::TouchPointReleased)) - : (touches.size() == 1) - ? (touches.at(0).state() & Qt::TouchPointReleased) - : 0; - if (touches.size() == 2) { - if ((e->type() == QEvent::TouchBegin) - || (e->type() == QEvent::TouchUpdate)) { - if (state->startAt.isNull()) { - state->startAt = touches.at(0).pos(); - state->cursorTop = widget->mapFromGlobal( - QCursor::pos()).y(); - state->finishByTopData = generateFinishByTop( - state->cursorTop); - if (!state->finishByTopData.callback) { - setOrientation(Qt::Vertical); - } - } else if (state->orientation) { - if ((*state->orientation) == Qt::Horizontal) { - state->lastAt = touches.at(0).pos(); - const auto delta = state->startAt - state->lastAt; - const auto ratio = delta.x() / threshold; - updateRatio(ratio); - constexpr auto kResetReachedOn = 0.95; - constexpr auto kBounceDuration = crl::time(500); - if (!state->reached && ratio >= 1.) { - state->reached = true; - state->animationReach.stop(); - state->animationReach.start( - animationReachCallback, - 0., - 1., - kBounceDuration); - base::Platform::Haptic(); - } else if (state->reached - && ratio < kResetReachedOn) { - state->reached = false; - } - } - } else { - state->lastAt = touches.at(0).pos(); - const auto delta = state->startAt - state->lastAt; - const auto diffXtoY = std::abs(delta.x()) - - std::abs(delta.y()); - if (diffXtoY > 0) { - setOrientation(Qt::Horizontal); - } else if (diffXtoY < 0) { - setOrientation(Qt::Vertical); - } else { - setOrientation(std::nullopt); - } - } - } + const auto released = [&](int index) { + return (touches.size() > index) + && (touches.at(index).state() & Qt::TouchPointReleased); + }; + const auto cancel = released(0) + || released(1) + || (touches.size() != (touchscreen ? 1 : 2)) + || (type == QEvent::TouchEnd) + || (type == QEvent::TouchCancel); + if (cancel) { + processEnd(touches.empty() + ? std::optional() + : (state->startAt - touches[0].pos())); + } else { + updateWith({ + .position = touches[0].pos(), + .delta = state->startAt - touches[0].pos(), + .touch = true, + }); + } + } break; + case QEvent::Wheel: { + const auto w = static_cast(e.get()); + const auto phase = w->phase(); + if (Platform::IsMac() || phase == Qt::NoScrollPhase) { + break; } - if ((e->type() == QEvent::TouchEnd) - || touches.empty() - || anyReleased - || (touches.size() > 2)) { - processEnd(t); + const auto cancel = w->buttons() + || (phase == Qt::ScrollEnd) + || (phase == Qt::ScrollMomentum); + if (cancel) { + processEnd(); + } else { + updateWith({ + .position = QPointF(), + .delta = state->delta - Ui::ScrollDelta(w), + .touch = false, + }); } - return base::EventFilterResult::Cancel; + } break; } return base::EventFilterResult::Continue; }; From f8c820f319c1e728e4059d27d60461abe601a8e4 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 3 Sep 2024 17:01:33 +0300 Subject: [PATCH 17/41] Fixed swipe-to-reply on macOS. --- Telegram/SourceFiles/history/history_view_swipe.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index c6f297dcf74660..e7034becebdd7d 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -140,12 +140,12 @@ void SetupSwipeHandler( const auto filter = [=](not_null e) { const auto type = e->type(); switch (type) { - case QEvent::Leave: + case QEvent::Leave: { if (state->orientation) { processEnd(); } - break; - case QEvent::MouseMove: + } break; + case QEvent::MouseMove: { if (state->orientation) { const auto m = static_cast(e.get()); if (std::abs(m->pos().y() - state->cursorTop) @@ -153,14 +153,14 @@ void SetupSwipeHandler( processEnd(); } } - break; + } break; case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: case QEvent::TouchCancel: { const auto t = static_cast(e.get()); const auto touchscreen = t->device() - && (t->device()->type() != base::TouchDevice::TouchScreen); + && (t->device()->type() == base::TouchDevice::TouchScreen); if (!Platform::IsMac() && !touchscreen) { break; } From 1648c31a222f6574f74862358a21926bd00690df Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 3 Sep 2024 17:16:51 +0300 Subject: [PATCH 18/41] Moved out swipe-to-reply setup to inner method in HistoryInner. --- .../history/history_inner_widget.cpp | 120 +++++++++--------- .../history/history_inner_widget.h | 1 + 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 7f35315b8131ec..e3662fc1647ea0 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -383,64 +383,6 @@ HistoryInner::HistoryInner( _migrated->delegateMixin()->setCurrent(this); _migrated->translateTo(_history->translatedTo()); } - HistoryView::SetupSwipeHandler(this, _scroll, [=, history = _history]( - HistoryView::ChatPaintGestureHorizontalData data) { - _gestureHorizontal = data; - const auto item = history->peer->owner().message( - history->peer->id, - MsgId{ data.msgBareId }); - if (item) { - repaintItem(item); - } - }, [=, show = controller->uiShow()](int cursorTop) { - auto result = HistoryView::SwipeHandlerFinishData(); - if (inSelectionMode()) { - return result; - } - enumerateItems([&]( - not_null view, - int itemtop, - int itembottom) { - if ((cursorTop < itemtop) - || (cursorTop > itembottom) - || !view->data()->isRegular() - || view->data()->isService()) { - return true; - } - const auto item = view->data(); - const auto canSendReply = CanSendReply(item); - const auto canReply = (canSendReply || item->allowsForward()); - if (!canReply) { - return true; - } - result.msgBareId = item->fullId().msg.bare; - result.callback = [=, itemId = item->fullId()] { - const auto still = show->session().data().message(itemId); - const auto selected = selectedQuote(still); - const auto replyToItemId = (selected.item - ? selected.item - : still)->fullId(); - if (canSendReply) { - _widget->replyToMessage({ - .messageId = replyToItemId, - .quote = selected.text, - .quoteOffset = selected.offset, - }); - if (!selected.text.empty()) { - _widget->clearSelected(); - } - } else { - HistoryView::Controls::ShowReplyToChatBox(show, { - .messageId = replyToItemId, - .quote = selected.text, - .quoteOffset = selected.offset, - }); - } - }; - return false; - }); - return result; - }); Window::ChatThemeValueFromPeer( controller, @@ -553,6 +495,7 @@ HistoryInner::HistoryInner( }, _scroll->lifetime()); setupSharingDisallowed(); + setupSwipeReply(); } void HistoryInner::reactionChosen(const ChosenReaction &reaction) { @@ -635,6 +578,67 @@ void HistoryInner::setupSharingDisallowed() { }, lifetime()); } +void HistoryInner::setupSwipeReply() { + HistoryView::SetupSwipeHandler(this, _scroll, [=, history = _history]( + HistoryView::ChatPaintGestureHorizontalData data) { + _gestureHorizontal = data; + const auto item = history->peer->owner().message( + history->peer->id, + MsgId{ data.msgBareId }); + if (item) { + repaintItem(item); + } + }, [=, show = _controller->uiShow()](int cursorTop) { + auto result = HistoryView::SwipeHandlerFinishData(); + if (inSelectionMode()) { + return result; + } + enumerateItems([&]( + not_null view, + int itemtop, + int itembottom) { + if ((cursorTop < itemtop) + || (cursorTop > itembottom) + || !view->data()->isRegular() + || view->data()->isService()) { + return true; + } + const auto item = view->data(); + const auto canSendReply = CanSendReply(item); + const auto canReply = (canSendReply || item->allowsForward()); + if (!canReply) { + return true; + } + result.msgBareId = item->fullId().msg.bare; + result.callback = [=, itemId = item->fullId()] { + const auto still = show->session().data().message(itemId); + const auto selected = selectedQuote(still); + const auto replyToItemId = (selected.item + ? selected.item + : still)->fullId(); + if (canSendReply) { + _widget->replyToMessage({ + .messageId = replyToItemId, + .quote = selected.text, + .quoteOffset = selected.offset, + }); + if (!selected.text.empty()) { + _widget->clearSelected(); + } + } else { + HistoryView::Controls::ShowReplyToChatBox(show, { + .messageId = replyToItemId, + .quote = selected.text, + .quoteOffset = selected.offset, + }); + } + }; + return false; + }); + return result; + }); +} + bool HistoryInner::hasSelectRestriction() const { if (!_sharingDisallowed.current()) { return false; diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 2507a09214358b..f4338a3ce040e5 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -420,6 +420,7 @@ class HistoryInner void reactionChosen(const ChosenReaction &reaction); void setupSharingDisallowed(); + void setupSwipeReply(); [[nodiscard]] bool hasCopyRestriction(HistoryItem *item = nullptr) const; [[nodiscard]] bool hasCopyMediaRestriction( not_null item) const; From 71e3cd227c9cabb3b87f4c9a8a233c0b5fddc08c Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 3 Sep 2024 18:04:55 +0300 Subject: [PATCH 19/41] Added initial swipe-to-reply to section for replies. --- .../history/view/history_view_list_widget.cpp | 8 +++ .../view/history_view_replies_section.cpp | 66 +++++++++++++++++++ .../view/history_view_replies_section.h | 6 ++ 3 files changed, 80 insertions(+) diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index a07fcfd5b00e3e..4031a4f3623330 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2305,6 +2305,11 @@ void ListWidget::paintUserpics( // paint the userpic if it intersects the painted rect if (userpicTop + st::msgPhotoSize > clip.top()) { const auto item = view->data(); + const auto hasTranslation = context.gestureHorizontal.ratio + && (context.gestureHorizontal.msgBareId == item->fullId().msg.bare); + if (hasTranslation) { + p.translate(context.gestureHorizontal.translation, 0); + } if (const auto from = item->displayFrom()) { from->paintUserpicLeft( p, @@ -2337,6 +2342,9 @@ void ListWidget::paintUserpics( } else { Unexpected("Corrupt forwarded information in message."); } + if (hasTranslation) { + p.translate(-context.gestureHorizontal.translation, 0); + } } return true; }); diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 07465b5b30b7b6..baf644137d0c44 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -24,6 +24,7 @@ For license and copyright information please follow this link: #include "history/history_drag_area.h" #include "history/history_item_components.h" #include "history/history_item_helpers.h" // GetErrorTextForSending. +#include "history/history_view_swipe.h" #include "ui/chat/pinned_bar.h" #include "ui/chat/chat_style.h" #include "ui/widgets/buttons.h" @@ -399,6 +400,7 @@ RepliesWidget::RepliesWidget( setupTopicViewer(); setupComposeControls(); + setupSwipeReply(); orderWidgets(); if (_pinnedBar) { @@ -865,6 +867,62 @@ void RepliesWidget::setupComposeControls() { } } +void RepliesWidget::setupSwipeReply() { + const auto can = [=](not_null still) { + const auto canSendReply = _topic + ? Data::CanSendAnything(_topic) + : Data::CanSendAnything(_history->peer); + const auto allowInAnotherChat = still && still->allowsForward(); + if (allowInAnotherChat && (_joinGroup || !canSendReply)) { + return true; + } else if (!_joinGroup && canSendReply) { + return true; + } + return false; + }; + HistoryView::SetupSwipeHandler(_inner, _scroll.get(), [=]( + HistoryView::ChatPaintGestureHorizontalData data) { + _gestureHorizontal = data; + const auto item = _history->peer->owner().message( + _history->peer->id, + MsgId{ data.msgBareId }); + if (item) { + _inner->update(); + // repaintItem(item); + } + }, [=, show = controller()->uiShow()](int cursorTop) { + auto result = HistoryView::SwipeHandlerFinishData(); + if (_inner->elementInSelectionMode()) { + return result; + } + const auto view = _inner->lookupItemByY(cursorTop); + if (!view->data()->isRegular() + || view->data()->isService()) { + return result; + } + if (!can(view->data())) { + return result; + } + + result.msgBareId = view->data()->fullId().msg.bare; + result.callback = [=, itemId = view->data()->fullId()] { + const auto still = show->session().data().message(itemId); + const auto view = _inner->viewByPosition(still->position()); + const auto selected = view->selectedQuote( + _inner->getSelectedTextRange(still)); + const auto replyToItemId = (selected.item + ? selected.item + : still)->fullId(); + _inner->replyToMessageRequestNotify({ + .messageId = replyToItemId, + .quote = selected.text, + .quoteOffset = selected.offset, + }); + }; + return result; + }); +} + void RepliesWidget::chooseAttach( std::optional overrideSendImagesAsPhotos) { _choosingAttach = false; @@ -2631,6 +2689,14 @@ void RepliesWidget::listAddTranslatedItems( } } +Ui::ChatPaintContext RepliesWidget::listPreparePaintContext( + Ui::ChatPaintContextArgs &&args) { + auto context = WindowListDelegate::listPreparePaintContext( + std::move(args)); + context.gestureHorizontal = _gestureHorizontal; + return context; +} + void RepliesWidget::setupEmptyPainter() { Expects(_topic != nullptr); diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index be572f4caaf4df..71321f14c5df43 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -11,6 +11,7 @@ For license and copyright information please follow this link: #include "window/section_memento.h" #include "history/view/history_view_corner_buttons.h" #include "history/view/history_view_list_widget.h" +#include "history/history_view_swipe_data.h" #include "data/data_messages.h" #include "base/timer.h" @@ -180,6 +181,8 @@ class RepliesWidget final History *listTranslateHistory() override; void listAddTranslatedItems( not_null tracker) override; + Ui::ChatPaintContext listPreparePaintContext( + Ui::ChatPaintContextArgs &&args) override; // CornerButtonsDelegate delegate. void cornerButtonsShowAtPosition( @@ -221,6 +224,7 @@ class RepliesWidget final void finishSending(); void setupComposeControls(); + void setupSwipeReply(); void setupRoot(); void setupRootView(); @@ -369,6 +373,8 @@ class RepliesWidget final HistoryView::CornerButtons _cornerButtons; rpl::lifetime _topicLifetime; + HistoryView::ChatPaintGestureHorizontalData _gestureHorizontal; + int _lastScrollTop = 0; int _topicReopenBarHeight = 0; int _scrollTopDelta = 0; From e8dd2b9e7b72a0fd7952f3d2180fbeff7926ecc9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 3 Sep 2024 22:14:32 +0400 Subject: [PATCH 20/41] Use only integer translations in reply swipe. --- .../SourceFiles/history/history_inner_widget.cpp | 16 ++++++++++------ .../SourceFiles/history/history_view_swipe.cpp | 2 +- .../history/history_view_swipe_data.h | 2 +- .../history/view/history_view_list_widget.cpp | 2 +- .../history/view/history_view_message.cpp | 2 +- .../view/history_view_replies_section.cpp | 15 +++++++++------ 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index e3662fc1647ea0..b7687266ef6578 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -581,12 +581,16 @@ void HistoryInner::setupSharingDisallowed() { void HistoryInner::setupSwipeReply() { HistoryView::SetupSwipeHandler(this, _scroll, [=, history = _history]( HistoryView::ChatPaintGestureHorizontalData data) { + const auto changed = (_gestureHorizontal.msgBareId != data.msgBareId) + || (_gestureHorizontal.translation != data.translation); _gestureHorizontal = data; - const auto item = history->peer->owner().message( - history->peer->id, - MsgId{ data.msgBareId }); - if (item) { - repaintItem(item); + if (changed) { + const auto item = history->peer->owner().message( + history->peer->id, + MsgId{ data.msgBareId }); + if (item) { + repaintItem(item); + } } }, [=, show = _controller->uiShow()](int cursorTop) { auto result = HistoryView::SwipeHandlerFinishData(); @@ -1230,7 +1234,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { // paint the userpic if it intersects the painted rect if (userpicTop + st::msgPhotoSize > clip.top()) { const auto item = view->data(); - const auto hasTranslation = _gestureHorizontal.ratio + const auto hasTranslation = _gestureHorizontal.translation && (_gestureHorizontal.msgBareId == item->fullId().msg.bare); if (hasTranslation) { p.translate(_gestureHorizontal.translation, 0); diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index e7034becebdd7d..81769891ada47f 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -48,7 +48,7 @@ void SetupSwipeHandler( update({ .ratio = std::clamp(ratio, 0., 1.5), .reachRatio = state->animationReach.value(0.), - .translation = (-std::clamp(ratio, 0., 1.5) * threshold), + .translation = int(base::SafeRound(-std::clamp(ratio, 0., 1.5) * threshold)), .msgBareId = state->finishByTopData.msgBareId, .cursorTop = state->cursorTop, }); diff --git a/Telegram/SourceFiles/history/history_view_swipe_data.h b/Telegram/SourceFiles/history/history_view_swipe_data.h index a08ef8e2c76909..c3dd9eb776d3aa 100644 --- a/Telegram/SourceFiles/history/history_view_swipe_data.h +++ b/Telegram/SourceFiles/history/history_view_swipe_data.h @@ -12,8 +12,8 @@ namespace HistoryView { struct ChatPaintGestureHorizontalData { float64 ratio = 0.; float64 reachRatio = 0.; - float64 translation = 0.; int64 msgBareId = 0; + int translation = 0; int cursorTop = 0; }; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 4031a4f3623330..c6b0fd066faa96 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2305,7 +2305,7 @@ void ListWidget::paintUserpics( // paint the userpic if it intersects the painted rect if (userpicTop + st::msgPhotoSize > clip.top()) { const auto item = view->data(); - const auto hasTranslation = context.gestureHorizontal.ratio + const auto hasTranslation = context.gestureHorizontal.translation && (context.gestureHorizontal.msgBareId == item->fullId().msg.bare); if (hasTranslation) { p.translate(context.gestureHorizontal.translation, 0); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 669ad90fa55630..c84cf1779f94e2 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1092,7 +1092,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { const auto item = data(); const auto media = this->media(); - const auto hasGesture = context.gestureHorizontal.ratio + const auto hasGesture = context.gestureHorizontal.translation && (context.gestureHorizontal.msgBareId == item->fullId().msg.bare); if (hasGesture) { p.translate(context.gestureHorizontal.translation, 0); diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index baf644137d0c44..def3156c202107 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -882,13 +882,16 @@ void RepliesWidget::setupSwipeReply() { }; HistoryView::SetupSwipeHandler(_inner, _scroll.get(), [=]( HistoryView::ChatPaintGestureHorizontalData data) { + const auto changed = (_gestureHorizontal.msgBareId != data.msgBareId) + || (_gestureHorizontal.translation != data.translation); _gestureHorizontal = data; - const auto item = _history->peer->owner().message( - _history->peer->id, - MsgId{ data.msgBareId }); - if (item) { - _inner->update(); - // repaintItem(item); + if (changed) { + const auto item = _history->peer->owner().message( + _history->peer->id, + MsgId{ data.msgBareId }); + if (item) { + _history->owner().requestItemRepaint(item); + } } }, [=, show = controller()->uiShow()](int cursorTop) { auto result = HistoryView::SwipeHandlerFinishData(); From dd100fb7096efe2a9b4923d3767da95dc4bc1471 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 09:59:05 +0300 Subject: [PATCH 21/41] Fixed back gesture responsiveness for swipe-to-reply on macOS. --- Telegram/SourceFiles/history/history_view_swipe.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index 81769891ada47f..9d76075c611b92 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -48,7 +48,8 @@ void SetupSwipeHandler( update({ .ratio = std::clamp(ratio, 0., 1.5), .reachRatio = state->animationReach.value(0.), - .translation = int(base::SafeRound(-std::clamp(ratio, 0., 1.5) * threshold)), + .translation = int( + base::SafeRound(-std::clamp(ratio, 0., 1.5) * threshold)), .msgBareId = state->finishByTopData.msgBareId, .cursorTop = state->cursorTop, }); @@ -171,7 +172,9 @@ void SetupSwipeHandler( }; const auto cancel = released(0) || released(1) - || (touches.size() != (touchscreen ? 1 : 2)) + || (touchscreen + ? (touches.size() != 1) + : (touches.size() <= 0 || touches.size() > 2)) || (type == QEvent::TouchEnd) || (type == QEvent::TouchCancel); if (cancel) { @@ -185,6 +188,7 @@ void SetupSwipeHandler( .touch = true, }); } + return base::EventFilterResult::Cancel; } break; case QEvent::Wheel: { const auto w = static_cast(e.get()); From 89c2ba4293a457500582a033a01cbd4a4bdd316f Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 10:05:47 +0300 Subject: [PATCH 22/41] Weakened gesture orientation check within swipe-to-reply. --- Telegram/SourceFiles/history/history_view_swipe.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index 9d76075c611b92..647f5f198e4e8b 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -110,9 +110,10 @@ void SetupSwipeHandler( state->delta = args.delta; const auto diffXtoY = std::abs(args.delta.x()) - std::abs(args.delta.y()); - if (diffXtoY > 0) { + constexpr auto kOrientationThreshold = 1.; + if (diffXtoY > kOrientationThreshold) { setOrientation(Qt::Horizontal); - } else if (diffXtoY < 0) { + } else if (diffXtoY < -kOrientationThreshold) { setOrientation(Qt::Vertical); } else { setOrientation(std::nullopt); From add5a6a0bea42f8258ec2f64f6c8e4a84683fc92 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 30 Aug 2024 12:54:49 +0300 Subject: [PATCH 23/41] Added debug util to ensure end of life of objects. --- Telegram/SourceFiles/stdafx.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index da801ff9aabd2c..92db569f15ffa2 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -111,6 +111,7 @@ For license and copyright information please follow this link: #include "base/algorithm.h" #include "base/basic_types.h" +#include "base/debug_destroy_informer.h" // _DEBUG only. #include "base/flat_set.h" #include "base/flat_map.h" #include "base/invoke_queued.h" From 54e5c06b4d06cbc7d60d64f1476b572c45f0d225 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 2 Sep 2024 21:57:26 +0400 Subject: [PATCH 24/41] Revert updated Harfbuzz-NG in Qt 5.15.15. This fixes the regression with text rendering in 100% scale. Fixes #28340. --- Telegram/build/prepare/prepare.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Telegram/build/prepare/prepare.py b/Telegram/build/prepare/prepare.py index ac027ffab8071c..b05f65cded04ed 100644 --- a/Telegram/build/prepare/prepare.py +++ b/Telegram/build/prepare/prepare.py @@ -449,7 +449,7 @@ def runStages(): tmp_zshrc_path = tmp_zshrc.name subprocess.run(['zsh', '--rcs', tmp_zshrc_path], env=modifiedEnv) os.remove(tmp_zshrc_path) - elif not run(command): + elif not run(' '.join(runCommand) + '\n'): print('FAILED :(') finish(1) finish(0) @@ -1543,6 +1543,7 @@ def runStages(): depends:patches/qtbase_""" + qt + """/*.patch cd qtbase win: + git revert --no-edit 6ad56dce34 setlocal enabledelayedexpansion for /r %%i in (..\\..\\patches\\qtbase_%QT%\\*) do ( git apply %%i -v From ab2e7f4c0361ea2b3481d91e40f5e8a187d27104 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 2 Sep 2024 22:21:59 +0400 Subject: [PATCH 25/41] Fix media viewer create on non-primary screen. --- Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 6baa8638a28bcb..90374064e67d73 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -816,6 +816,7 @@ void OverlayWidget::moveToScreen(bool inMove) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) _window->setScreen(activeWindowScreen); #else // Qt >= 6.0.0 + _window->createWinId(); window()->setScreen(activeWindowScreen); #endif // Qt < 6.0.0 DEBUG_LOG(("Viewer Pos: New actual screen: %1") From 4430bd03288407ba939a1425179bca326508f370 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 3 Sep 2024 11:50:39 +0400 Subject: [PATCH 26/41] Improve lottie icon layout in group calls. --- .../ui/controls/call_mute_button.cpp | 60 ++++++++++++------- .../ui/controls/call_mute_button.h | 4 +- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/Telegram/SourceFiles/ui/controls/call_mute_button.cpp b/Telegram/SourceFiles/ui/controls/call_mute_button.cpp index df7296b3d6fc57..b142eb7ea04806 100644 --- a/Telegram/SourceFiles/ui/controls/call_mute_button.cpp +++ b/Telegram/SourceFiles/ui/controls/call_mute_button.cpp @@ -82,6 +82,28 @@ constexpr auto kRadialFinishArcShift = 1200; : type; }; +[[nodiscard]] QSize AdjustedLottieSize( + not_null st) { + const auto &button = st->active.button; + const auto left = (button.width - st->lottieSize.width()) / 2; + const auto size = button.width - 2 * left; + return QSize(size, size); +} + +[[nodiscard]] int AdjustedBgSize( + not_null st) { + const auto &button = st->active.button; + const auto left = (button.width - st->active.bgSize) / 2; + return button.width - 2 * left; +} + +[[nodiscard]] int AdjustedBgSkip( + not_null st) { + const auto &button = st->active.button; + const auto bgSize = AdjustedBgSize(st); + return (button.width - bgSize) / 2; +} + auto MuteBlobs() { return std::vector{ { @@ -515,9 +537,12 @@ CallMuteButton::CallMuteButton( CallMuteButtonState initial) : _state(initial) , _st(&st) +, _lottieSize(AdjustedLottieSize(_st)) +, _bgSize(AdjustedBgSize(_st)) +, _bgSkip(AdjustedBgSkip(_st)) , _blobs(base::make_unique_q( parent, - _st->active.bgSize, + _bgSize, rpl::combine( PowerSaving::OnValue(PowerSaving::kCalls), std::move(hideBlobs), @@ -593,13 +618,13 @@ void CallMuteButton::refreshIcons() { _icons[0].emplace(Lottie::IconDescriptor{ .path = u":/icons/calls/voice.lottie"_q, .color = &st::groupCallIconFg, - .sizeOverride = _st->lottieSize, + .sizeOverride = _lottieSize, .frame = (_iconState.index ? 0 : _iconState.frameTo), }); _icons[1].emplace(Lottie::IconDescriptor{ .path = u":/icons/calls/hands.lottie"_q, .color = &st::groupCallIconFg, - .sizeOverride = _st->lottieSize, + .sizeOverride = _lottieSize, .frame = (_iconState.index ? _iconState.frameTo : 0), }); @@ -813,7 +838,7 @@ void CallMuteButton::init() { // Icon rect. _content->sizeValue( ) | rpl::start_with_next([=](QSize size) { - const auto icon = _st->lottieSize; + const auto icon = _lottieSize; _muteIconRect = QRect( (size.width() - icon.width()) / 2, _st->lottieTop, @@ -858,8 +883,8 @@ void CallMuteButton::init() { InfiniteRadialAnimation::Draw( p, r, - _st->active.bgPosition, - QSize(_st->active.bgSize, _st->active.bgSize), + QPoint(_bgSkip, _bgSkip), + QSize(_bgSize, _bgSize), _content->width(), QPen(_radialInfo.st.color), _radialInfo.st.thickness); @@ -870,8 +895,8 @@ void CallMuteButton::init() { InfiniteRadialAnimation::Draw( p, std::move(state), - _st->active.bgPosition, - QSize(_st->active.bgSize, _st->active.bgSize), + QPoint(_bgSkip, _bgSkip), + QSize(_bgSize, _bgSize), _content->width(), QPen(_radialInfo.st.color), _radialInfo.st.thickness); @@ -1027,6 +1052,9 @@ void CallMuteButton::setStyle(const style::CallMuteButton &st) { return; } _st = &st; + _lottieSize = AdjustedLottieSize(_st); + _bgSize = AdjustedBgSize(_st); + _bgSkip = AdjustedBgSkip(_st); const auto &button = _st->active.button; _content->resize(button.width, button.height); _blobs->setDiameter(_st->active.bgSize); @@ -1057,21 +1085,13 @@ rpl::producer CallMuteButton::clicks() { } QSize CallMuteButton::innerSize() const { - return innerGeometry().size(); -} - -QRect CallMuteButton::innerGeometry() const { - const auto &skip = _st->active.outerRadius; - return QRect( - _content->x(), - _content->y(), - _content->width() - 2 * skip, - _content->width() - 2 * skip); + return QSize( + _content->width() - 2 * _bgSkip, + _content->width() - 2 * _bgSkip); } void CallMuteButton::moveInner(QPoint position) { - const auto &skip = _st->active.outerRadius; - _content->move(position - QPoint(skip, skip)); + _content->move(position - QPoint(_bgSkip, _bgSkip)); { const auto offset = QPoint( diff --git a/Telegram/SourceFiles/ui/controls/call_mute_button.h b/Telegram/SourceFiles/ui/controls/call_mute_button.h index b6755f543168ef..455c9448515df7 100644 --- a/Telegram/SourceFiles/ui/controls/call_mute_button.h +++ b/Telegram/SourceFiles/ui/controls/call_mute_button.h @@ -73,7 +73,6 @@ class CallMuteButton final : private AbstractTooltipShower { [[nodiscard]] rpl::producer clicks(); [[nodiscard]] QSize innerSize() const; - [[nodiscard]] QRect innerGeometry() const; void moveInner(QPoint position); void shake(); @@ -165,6 +164,9 @@ class CallMuteButton final : private AbstractTooltipShower { HandleMouseState _handleMouseState = HandleMouseState::Enabled; not_null _st; + QSize _lottieSize; + int _bgSize = 0; + int _bgSkip = 0; const base::unique_qptr _blobs; const base::unique_qptr _content; From 1f4a8d7eb618f2ef1d5a160db792ea49c00786d2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 4 Sep 2024 14:45:07 +0400 Subject: [PATCH 27/41] Fix build with MSVC. --- Telegram/SourceFiles/history/history_view_swipe.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index 647f5f198e4e8b..d878ffbd4b26a9 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -48,9 +48,9 @@ void SetupSwipeHandler( update({ .ratio = std::clamp(ratio, 0., 1.5), .reachRatio = state->animationReach.value(0.), + .msgBareId = state->finishByTopData.msgBareId, .translation = int( base::SafeRound(-std::clamp(ratio, 0., 1.5) * threshold)), - .msgBareId = state->finishByTopData.msgBareId, .cursorTop = state->cursorTop, }); }; From 5a2667c71e79574b9c35ab82c9d9e29afdf1d7aa Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 4 Sep 2024 14:45:35 +0400 Subject: [PATCH 28/41] Fix reply previews to blockquotes / codeblocks. --- Telegram/SourceFiles/history/history_item.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index e0a96d7f6a1e83..004720dfd55e1e 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -3454,9 +3454,10 @@ ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const { return _media->toPreview(options); } else if (!emptyText()) { return { - .text = st::wrap_rtl(options.translated - ? translatedText() - : _text) + // wrap_rtl "adds" a newline in case text starts with quote. + // So we remove those by DialogsPreviewText call. + .text = st::wrap_rtl(Dialogs::Ui::DialogsPreviewText( + options.translated ? translatedText() : _text)) }; } return {}; From 20a5e0ba7329383769717a5f94eeedfc8b18a865 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 4 Sep 2024 14:56:50 +0400 Subject: [PATCH 29/41] Fix controls layout after adding a bot to a group. Fixes https://bugs.telegram.org/c/19451 --- Telegram/SourceFiles/history/history_widget.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 957b76b4d73966..573f130fc16721 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6469,8 +6469,11 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) { : nullptr; changed = _keyboard->updateMarkup(keyboardItem, force); } - updateCmdStartShown(); + const auto controlsChanged = updateCmdStartShown(); if (!changed) { + if (controlsChanged) { + updateControlsGeometry(); + } return; } else if (_keyboard->forMsgId() != wasMsgId) { _kbScroll->scrollTo({ 0, 0 }); From 8d0f66d5627552c8dde6ac25609ec68449001e51 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 4 Sep 2024 14:06:11 +0200 Subject: [PATCH 30/41] Fix touchscreen history scrolling. --- Telegram/SourceFiles/history/history_view_swipe.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index d878ffbd4b26a9..42d3ec1606aeec 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -189,7 +189,9 @@ void SetupSwipeHandler( .touch = true, }); } - return base::EventFilterResult::Cancel; + return (touchscreen && state->orientation != Qt::Horizontal) + ? base::EventFilterResult::Continue + : base::EventFilterResult::Cancel; } break; case QEvent::Wheel: { const auto w = static_cast(e.get()); From b82fa3112c9502eabadccabbbb82316140788dd2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 4 Sep 2024 15:56:16 +0200 Subject: [PATCH 31/41] Improve touchscreen swipt-to-reply. --- .../history/history_inner_widget.cpp | 23 +++++++++--- .../history/history_inner_widget.h | 1 + .../history/history_view_swipe.cpp | 36 +++++++++++++++---- .../SourceFiles/history/history_view_swipe.h | 3 +- .../history/view/history_view_list_widget.cpp | 29 ++++++++++++--- .../history/view/history_view_list_widget.h | 2 ++ .../view/history_view_replies_section.cpp | 2 +- 7 files changed, 77 insertions(+), 19 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index b7687266ef6578..c38ad8e0eb7ca4 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -640,7 +640,7 @@ void HistoryInner::setupSwipeReply() { return false; }); return result; - }); + }, _touchMaybeSelecting.value()); } bool HistoryInner::hasSelectRestriction() const { @@ -1497,6 +1497,7 @@ void HistoryInner::touchEvent(QTouchEvent *e) { _touchScroll = _touchSelect = false; _horizontalScrollLocked = false; _touchScrollState = Ui::TouchScrollState::Manual; + _touchMaybeSelecting = false; mouseActionCancel(); return; } @@ -1519,6 +1520,7 @@ void HistoryInner::touchEvent(QTouchEvent *e) { _touchInProgress = true; _horizontalScrollLocked = false; if (_touchScrollState == Ui::TouchScrollState::Auto) { + _touchMaybeSelecting = false; _touchScrollState = Ui::TouchScrollState::Acceleration; _touchWaitingAcceleration = true; _touchAccelerationTime = crl::now(); @@ -1526,6 +1528,7 @@ void HistoryInner::touchEvent(QTouchEvent *e) { _touchStart = _touchPos; } else { _touchScroll = false; + _touchMaybeSelecting = true; _touchSelectTimer.callOnce(QApplication::startDragTime()); } _touchSelect = false; @@ -1539,6 +1542,7 @@ void HistoryInner::touchEvent(QTouchEvent *e) { mouseActionUpdate(_touchPos); } else if (!_touchScroll && (_touchPos - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { _touchSelectTimer.cancel(); + _touchMaybeSelecting = false; _touchScroll = true; touchUpdateSpeed(); } @@ -1560,11 +1564,18 @@ void HistoryInner::touchEvent(QTouchEvent *e) { return; } _touchInProgress = false; + const auto notMoved = (_touchPos - _touchStart).manhattanLength() + < QApplication::startDragDistance(); auto weak = Ui::MakeWeak(this); if (_touchSelect) { - mouseActionFinish(_touchPos, Qt::RightButton); - QContextMenuEvent contextMenu(QContextMenuEvent::Mouse, mapFromGlobal(_touchPos), _touchPos); - showContextMenu(&contextMenu, true); + if (notMoved || _touchMaybeSelecting.current()) { + mouseActionFinish(_touchPos, Qt::RightButton); + auto contextMenu = QContextMenuEvent( + QContextMenuEvent::Mouse, + mapFromGlobal(_touchPos), + _touchPos); + showContextMenu(&contextMenu, true); + } _touchScroll = false; } else if (_touchScroll) { if (_touchScrollState == Ui::TouchScrollState::Manual) { @@ -1582,12 +1593,13 @@ void HistoryInner::touchEvent(QTouchEvent *e) { _touchWaitingAcceleration = false; _touchPrevPosValid = false; } - } else { // One short tap is like left mouse click. + } else if (notMoved) { // One short tap is like left mouse click. mouseActionStart(_touchPos, Qt::LeftButton); mouseActionFinish(_touchPos, Qt::LeftButton); } if (weak) { _touchSelectTimer.cancel(); + _touchMaybeSelecting = false; _touchSelect = false; } } break; @@ -3789,6 +3801,7 @@ MessageIdsList HistoryInner::getSelectedItems() const { void HistoryInner::onTouchSelect() { _touchSelect = true; + _touchMaybeSelecting = true; mouseActionStart(_touchPos, Qt::LeftButton); } diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index f4338a3ce040e5..030a53adcc9f59 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -513,6 +513,7 @@ class HistoryInner bool _touchSelect = false; bool _touchInProgress = false; QPoint _touchStart, _touchPrevPos, _touchPos; + rpl::variable _touchMaybeSelecting; base::Timer _touchSelectTimer; Ui::DraggingScrollManager _selectScroll; diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index 42d3ec1606aeec..8d7648673619b1 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -25,7 +25,8 @@ void SetupSwipeHandler( not_null widget, not_null scroll, Fn update, - Fn generateFinishByTop) { + Fn generateFinishByTop, + rpl::producer dontStart) { constexpr auto kThresholdWidth = 50; const auto threshold = style::ConvertFloatScale(kThresholdWidth); struct State { @@ -37,6 +38,7 @@ void SetupSwipeHandler( QPointF startAt; QPointF delta; int cursorTop = 0; + bool dontStart = false; bool started = false; bool reached = false; bool touch = false; @@ -44,6 +46,12 @@ void SetupSwipeHandler( rpl::lifetime lifetime; }; const auto state = widget->lifetime().make_state(); + std::move( + dontStart + ) | rpl::start_with_next([=](bool dontStart) { + state->dontStart = dontStart; + }, state->lifetime); + const auto updateRatio = [=](float64 ratio) { update({ .ratio = std::clamp(ratio, 0., 1.5), @@ -83,12 +91,15 @@ void SetupSwipeHandler( state->reached = false; }; scroll->scrolls() | rpl::start_with_next([=] { - processEnd(); + if (state->orientation != Qt::Vertical) { + processEnd(); + } }, state->lifetime); const auto animationReachCallback = [=] { updateRatio(state->delta.x() / threshold); }; struct UpdateArgs { + QPoint globalCursor; QPointF position; QPointF delta; bool touch = false; @@ -99,8 +110,7 @@ void SetupSwipeHandler( state->touch = args.touch; state->startAt = args.position; state->delta = QPointF(); - state->cursorTop = widget->mapFromGlobal( - QCursor::pos()).y(); + state->cursorTop = widget->mapFromGlobal(args.globalCursor).y(); state->finishByTopData = generateFinishByTop( state->cursorTop); if (!state->finishByTopData.callback) { @@ -112,7 +122,9 @@ void SetupSwipeHandler( - std::abs(args.delta.y()); constexpr auto kOrientationThreshold = 1.; if (diffXtoY > kOrientationThreshold) { - setOrientation(Qt::Horizontal); + if (!state->dontStart) { + setOrientation(Qt::Horizontal); + } } else if (diffXtoY < -kOrientationThreshold) { setOrientation(Qt::Vertical); } else { @@ -143,12 +155,12 @@ void SetupSwipeHandler( const auto type = e->type(); switch (type) { case QEvent::Leave: { - if (state->orientation) { + if (state->orientation == Qt::Horizontal) { processEnd(); } } break; case QEvent::MouseMove: { - if (state->orientation) { + if (state->orientation == Qt::Horizontal) { const auto m = static_cast(e.get()); if (std::abs(m->pos().y() - state->cursorTop) > QApplication::startDragDistance()) { @@ -165,6 +177,9 @@ void SetupSwipeHandler( && (t->device()->type() == base::TouchDevice::TouchScreen); if (!Platform::IsMac() && !touchscreen) { break; + } else if (type == QEvent::TouchBegin) { + // Reset state in case we lost some TouchEnd. + processEnd(); } const auto &touches = t->touchPoints(); const auto released = [&](int index) { @@ -184,6 +199,9 @@ void SetupSwipeHandler( : (state->startAt - touches[0].pos())); } else { updateWith({ + .globalCursor = (touchscreen + ? touches[0].screenPos().toPoint() + : QCursor::pos()), .position = touches[0].pos(), .delta = state->startAt - touches[0].pos(), .touch = true, @@ -198,6 +216,9 @@ void SetupSwipeHandler( const auto phase = w->phase(); if (Platform::IsMac() || phase == Qt::NoScrollPhase) { break; + } else if (phase == Qt::ScrollBegin) { + // Reset state in case we lost some TouchEnd. + processEnd(); } const auto cancel = w->buttons() || (phase == Qt::ScrollEnd) @@ -206,6 +227,7 @@ void SetupSwipeHandler( processEnd(); } else { updateWith({ + .globalCursor = w->globalPos(), .position = QPointF(), .delta = state->delta - Ui::ScrollDelta(w), .touch = false, diff --git a/Telegram/SourceFiles/history/history_view_swipe.h b/Telegram/SourceFiles/history/history_view_swipe.h index e7fb2ea4a53dec..fe9ec2ea02f6ff 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.h +++ b/Telegram/SourceFiles/history/history_view_swipe.h @@ -25,6 +25,7 @@ void SetupSwipeHandler( not_null widget, not_null scroll, Fn update, - Fn generateFinishByTop); + Fn generateFinishByTop, + rpl::producer dontStart = nullptr); } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index c6b0fd066faa96..e54affc2c78a18 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2940,6 +2940,7 @@ void ListWidget::touchEvent(QTouchEvent *e) { _touchSelectTimer.cancel(); _touchScroll = _touchSelect = false; _touchScrollState = Ui::TouchScrollState::Manual; + _touchMaybeSelecting = false; mouseActionCancel(); return; } @@ -2960,6 +2961,7 @@ void ListWidget::touchEvent(QTouchEvent *e) { _touchInProgress = true; if (_touchScrollState == Ui::TouchScrollState::Auto) { + _touchMaybeSelecting = false; _touchScrollState = Ui::TouchScrollState::Acceleration; _touchWaitingAcceleration = true; _touchAccelerationTime = crl::now(); @@ -2967,6 +2969,7 @@ void ListWidget::touchEvent(QTouchEvent *e) { _touchStart = _touchPos; } else { _touchScroll = false; + _touchMaybeSelecting = true; _touchSelectTimer.callOnce(QApplication::startDragTime()); } _touchSelect = false; @@ -2979,6 +2982,7 @@ void ListWidget::touchEvent(QTouchEvent *e) { mouseActionUpdate(_touchPos); } else if (!_touchScroll && (_touchPos - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { _touchSelectTimer.cancel(); + _touchMaybeSelecting = false; _touchScroll = true; touchUpdateSpeed(); } @@ -2996,13 +3000,22 @@ void ListWidget::touchEvent(QTouchEvent *e) { } break; case QEvent::TouchEnd: { - if (!_touchInProgress) return; + if (!_touchInProgress) { + return; + } _touchInProgress = false; auto weak = Ui::MakeWeak(this); + const auto notMoved = (_touchPos - _touchStart).manhattanLength() + < QApplication::startDragDistance(); if (_touchSelect) { - mouseActionFinish(_touchPos, Qt::RightButton); - QContextMenuEvent contextMenu(QContextMenuEvent::Mouse, mapFromGlobal(_touchPos), _touchPos); - showContextMenu(&contextMenu, true); + if (notMoved || _touchMaybeSelecting.current()) { + mouseActionFinish(_touchPos, Qt::RightButton); + auto contextMenu = QContextMenuEvent( + QContextMenuEvent::Mouse, + mapFromGlobal(_touchPos), + _touchPos); + showContextMenu(&contextMenu, true); + } _touchScroll = false; } else if (_touchScroll) { if (_touchScrollState == Ui::TouchScrollState::Manual) { @@ -3019,12 +3032,13 @@ void ListWidget::touchEvent(QTouchEvent *e) { _touchWaitingAcceleration = false; _touchPrevPosValid = false; } - } else { // One short tap is like left mouse click. + } else if (notMoved) { // One short tap is like left mouse click. mouseActionStart(_touchPos, Qt::LeftButton); mouseActionFinish(_touchPos, Qt::LeftButton); } if (weak) { _touchSelectTimer.cancel(); + _touchMaybeSelecting = false; _touchSelect = false; } } break; @@ -3064,6 +3078,10 @@ void ListWidget::touchScrollUpdated(const QPoint &screenPos) { touchUpdateSpeed(); } +rpl::producer ListWidget::touchMaybeSelectingValue() const { + return _touchMaybeSelecting.value(); +} + void ListWidget::enterEventHook(QEnterEvent *e) { mouseActionUpdate(QCursor::pos()); return TWidget::enterEventHook(e); @@ -3120,6 +3138,7 @@ void ListWidget::updateDragSelection() { void ListWidget::onTouchSelect() { _touchSelect = true; + _touchMaybeSelecting = true; mouseActionStart(_touchPos, Qt::LeftButton); } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index d0507474f40fbf..09121d3570a108 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -327,6 +327,7 @@ class ListWidget final void selectItemAsGroup(not_null item); void touchScrollUpdated(const QPoint &screenPos); + [[nodiscard]] rpl::producer touchMaybeSelectingValue() const; [[nodiscard]] bool loadedAtTopKnown() const; [[nodiscard]] bool loadedAtTop() const; @@ -830,6 +831,7 @@ class ListWidget final bool _touchSelect = false; bool _touchInProgress = false; QPoint _touchStart, _touchPrevPos, _touchPos; + rpl::variable _touchMaybeSelecting; base::Timer _touchSelectTimer; Ui::DraggingScrollManager _selectScroll; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index def3156c202107..e54af4e2e362ed 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -923,7 +923,7 @@ void RepliesWidget::setupSwipeReply() { }); }; return result; - }); + }, _inner->touchMaybeSelectingValue()); } void RepliesWidget::chooseAttach( From 18c9ee093bad81e581f9bd79c93738c6fbae4efa Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 14:44:21 +0300 Subject: [PATCH 32/41] Fixed unwanted top offset of dialogs widget when float player opened. --- Telegram/SourceFiles/dialogs/dialogs_widget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 2e7568fc0275d3..44f558c103d410 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -3326,7 +3326,9 @@ void Widget::updateControlsGeometry() { } const auto wasScrollTop = _scroll->scrollTop(); - const auto newScrollTop = (_topDelta < 0 && wasScrollTop <= 0) + const auto newScrollTop = (wasScrollTop == 0) + ? wasScrollTop + : (_topDelta < 0 && wasScrollTop <= 0) ? wasScrollTop : (wasScrollTop + _topDelta); From c589ee1ca5398f403b627db9311d2116dd11140e Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 15:16:15 +0300 Subject: [PATCH 33/41] Fixed overlap of reply icon on left swipe of message with right action. --- Telegram/SourceFiles/history/view/history_view_message.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index c84cf1779f94e2..fd8e104619485a 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -1493,6 +1493,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { constexpr auto kShiftRatio = 1.5; constexpr auto kBouncePart = 0.25; + constexpr auto kMaxHeightRatio = 3.5; constexpr auto kStrokeWidth = 2.; constexpr auto kWaveWidth = 10.; const auto isLeftSize = (!context.outbg) @@ -1501,7 +1502,10 @@ void Message::draw(Painter &p, const PaintContext &context) const { const auto reachRatio = context.gestureHorizontal.reachRatio; const auto size = st::historyFastShareSize; const auto outerWidth = st::historySwipeIconSkip - + (isLeftSize ? rect::right(g) : width()); + + (isLeftSize ? rect::right(g) : width()) + + ((g.height() < size * kMaxHeightRatio) + ? rightActionSize().value_or(QSize()).width() + : 0); const auto rect = QRectF( outerWidth - (size * kShiftRatio * context.gestureHorizontal.ratio) From 96b7755cde53aae73d5996c2800e4d50b7b9113a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 15:35:19 +0300 Subject: [PATCH 34/41] Fixed updating of message on bounce animation of swipe-on-reply icon. --- .../history/history_inner_widget.cpp | 3 ++- .../history/history_view_swipe.cpp | 21 +++++++++---------- .../view/history_view_replies_section.cpp | 3 ++- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index c38ad8e0eb7ca4..a8911f2b384b8a 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -582,7 +582,8 @@ void HistoryInner::setupSwipeReply() { HistoryView::SetupSwipeHandler(this, _scroll, [=, history = _history]( HistoryView::ChatPaintGestureHorizontalData data) { const auto changed = (_gestureHorizontal.msgBareId != data.msgBareId) - || (_gestureHorizontal.translation != data.translation); + || (_gestureHorizontal.translation != data.translation) + || (_gestureHorizontal.reachRatio != data.reachRatio); _gestureHorizontal = data; if (changed) { const auto item = history->peer->owner().message( diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index 8d7648673619b1..64a6f811f1f7d8 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -33,6 +33,7 @@ void SetupSwipeHandler( base::unique_qptr filter; Ui::Animations::Simple animationReach; Ui::Animations::Simple animationEnd; + ChatPaintGestureHorizontalData data; SwipeHandlerFinishData finishByTopData; std::optional orientation; QPointF startAt; @@ -53,14 +54,12 @@ void SetupSwipeHandler( }, state->lifetime); const auto updateRatio = [=](float64 ratio) { - update({ - .ratio = std::clamp(ratio, 0., 1.5), - .reachRatio = state->animationReach.value(0.), - .msgBareId = state->finishByTopData.msgBareId, - .translation = int( - base::SafeRound(-std::clamp(ratio, 0., 1.5) * threshold)), - .cursorTop = state->cursorTop, - }); + state->data.ratio = std::clamp(ratio, 0., 1.5), + state->data.msgBareId = state->finishByTopData.msgBareId; + state->data.translation = int( + base::SafeRound(-std::clamp(ratio, 0., 1.5) * threshold)); + state->data.cursorTop = state->cursorTop; + update(state->data); }; const auto setOrientation = [=](std::optional o) { state->orientation = o; @@ -78,7 +77,6 @@ void SetupSwipeHandler( widget, state->finishByTopData.callback); } - state->animationReach.stop(); state->animationEnd.stop(); state->animationEnd.start( updateRatio, @@ -95,8 +93,9 @@ void SetupSwipeHandler( processEnd(); } }, state->lifetime); - const auto animationReachCallback = [=] { - updateRatio(state->delta.x() / threshold); + const auto animationReachCallback = [=](float64 value) { + state->data.reachRatio = value; + update(state->data); }; struct UpdateArgs { QPoint globalCursor; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index e54af4e2e362ed..69e60a5f3b2073 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -883,7 +883,8 @@ void RepliesWidget::setupSwipeReply() { HistoryView::SetupSwipeHandler(_inner, _scroll.get(), [=]( HistoryView::ChatPaintGestureHorizontalData data) { const auto changed = (_gestureHorizontal.msgBareId != data.msgBareId) - || (_gestureHorizontal.translation != data.translation); + || (_gestureHorizontal.translation != data.translation) + || (_gestureHorizontal.reachRatio != data.reachRatio); _gestureHorizontal = data; if (changed) { const auto item = _history->peer->owner().message( From 52e42f23ab9ff4712cdea094df882b837a1faba0 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 15:45:07 +0300 Subject: [PATCH 35/41] Improved animation speed on release of swipe-on-reply with various x. --- Telegram/SourceFiles/history/history_view_swipe.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index 64a6f811f1f7d8..b028f696928804 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -28,6 +28,7 @@ void SetupSwipeHandler( Fn generateFinishByTop, rpl::producer dontStart) { constexpr auto kThresholdWidth = 50; + constexpr auto kMaxRatio = 1.5; const auto threshold = style::ConvertFloatScale(kThresholdWidth); struct State { base::unique_qptr filter; @@ -54,10 +55,10 @@ void SetupSwipeHandler( }, state->lifetime); const auto updateRatio = [=](float64 ratio) { - state->data.ratio = std::clamp(ratio, 0., 1.5), + state->data.ratio = std::clamp(ratio, 0., kMaxRatio), state->data.msgBareId = state->finishByTopData.msgBareId; state->data.translation = int( - base::SafeRound(-std::clamp(ratio, 0., 1.5) * threshold)); + base::SafeRound(-std::clamp(ratio, 0., kMaxRatio) * threshold)); state->data.cursorTop = state->cursorTop; update(state->data); }; @@ -71,7 +72,10 @@ void SetupSwipeHandler( }; const auto processEnd = [=](std::optional delta = {}) { if (state->orientation == Qt::Horizontal) { - const auto ratio = delta.value_or(state->delta).x() / threshold; + const auto ratio = std::clamp( + delta.value_or(state->delta).x() / threshold, + 0., + kMaxRatio); if ((ratio >= 1) && state->finishByTopData.callback) { Ui::PostponeCall( widget, @@ -82,7 +86,7 @@ void SetupSwipeHandler( updateRatio, ratio, 0., - st::slideWrapDuration); + std::min(1., ratio) * st::slideWrapDuration); } setOrientation(std::nullopt); state->started = false; From 5bd45e9a208dc5e8a3ae9a6b7d5b30523346e20e Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 16:04:42 +0300 Subject: [PATCH 36/41] Fixed updating of left userpic with offset from swipe-on-reply. --- .../SourceFiles/history/history_inner_widget.cpp | 15 ++++++++++++--- .../history/view/history_view_list_widget.cpp | 11 ++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index a8911f2b384b8a..1b0ff5bb0886ef 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1235,10 +1235,19 @@ void HistoryInner::paintEvent(QPaintEvent *e) { // paint the userpic if it intersects the painted rect if (userpicTop + st::msgPhotoSize > clip.top()) { const auto item = view->data(); - const auto hasTranslation = _gestureHorizontal.translation - && (_gestureHorizontal.msgBareId == item->fullId().msg.bare); + const auto hasTranslation = context.gestureHorizontal.translation + && (context.gestureHorizontal.msgBareId + == item->fullId().msg.bare); if (hasTranslation) { - p.translate(_gestureHorizontal.translation, 0); + p.translate(context.gestureHorizontal.translation, 0); + update( + QRect( + st::historyPhotoLeft + + context.gestureHorizontal.translation, + userpicTop, + st::msgPhotoSize + - context.gestureHorizontal.translation, + st::msgPhotoSize)); } if (const auto from = item->displayFrom()) { Dialogs::Ui::PaintUserpic( diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index e54affc2c78a18..6f6484dc9a84b0 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2306,9 +2306,18 @@ void ListWidget::paintUserpics( if (userpicTop + st::msgPhotoSize > clip.top()) { const auto item = view->data(); const auto hasTranslation = context.gestureHorizontal.translation - && (context.gestureHorizontal.msgBareId == item->fullId().msg.bare); + && (context.gestureHorizontal.msgBareId + == item->fullId().msg.bare); if (hasTranslation) { p.translate(context.gestureHorizontal.translation, 0); + update( + QRect( + st::historyPhotoLeft + + context.gestureHorizontal.translation, + userpicTop, + st::msgPhotoSize + - context.gestureHorizontal.translation, + st::msgPhotoSize)); } if (const auto from = item->displayFrom()) { from->paintUserpicLeft( From 6a45a862ddc75cbcb43b052ea26e1c9057fadc71 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 16:11:42 +0300 Subject: [PATCH 37/41] Removed wheel events from scale slider in section of main settings. --- .../boosts/create_giveaway_box.cpp | 15 +++------------ Telegram/SourceFiles/settings/settings_common.cpp | 7 +++++-- Telegram/SourceFiles/settings/settings_common.h | 3 ++- Telegram/SourceFiles/settings/settings_main.cpp | 3 ++- .../SourceFiles/ui/widgets/continuous_sliders.h | 11 +++++++++++ 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp b/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp index 4c99284a4dec2a..58019ce8462bd4 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp @@ -462,19 +462,10 @@ void CreateGiveawayBox( const auto &padding = st::giveawayGiftCodeSliderPadding; Ui::AddSkip(sliderContainer, padding.top()); - class Slider : public Ui::MediaSlider { - public: - using Ui::MediaSlider::MediaSlider; - - protected: - void wheelEvent(QWheelEvent *e) override { - e->ignore(); - } - - }; - const auto slider = sliderContainer->add( - object_ptr(sliderContainer, st::settingsScale), + object_ptr( + sliderContainer, + st::settingsScale), st::boxRowPadding); Ui::AddSkip(sliderContainer, padding.bottom()); slider->resize(slider->width(), st::settingsScale.seekSize.height()); diff --git a/Telegram/SourceFiles/settings/settings_common.cpp b/Telegram/SourceFiles/settings/settings_common.cpp index 4480611675d2bd..77cdd80470426d 100644 --- a/Telegram/SourceFiles/settings/settings_common.cpp +++ b/Telegram/SourceFiles/settings/settings_common.cpp @@ -265,14 +265,17 @@ SliderWithLabel MakeSliderWithLabel( const style::MediaSlider &sliderSt, const style::FlatLabel &labelSt, int skip, - int minLabelWidth) { + int minLabelWidth, + bool ignoreWheel) { auto result = object_ptr(parent); const auto raw = result.data(); const auto height = std::max( sliderSt.seekSize.height(), labelSt.style.font->height); raw->resize(sliderSt.seekSize.width(), height); - const auto slider = Ui::CreateChild(raw, sliderSt); + const auto slider = ignoreWheel + ? Ui::CreateChild(raw, sliderSt) + : Ui::CreateChild(raw, sliderSt); const auto label = Ui::CreateChild(raw, labelSt); slider->resize(slider->width(), sliderSt.seekSize.height()); rpl::combine( diff --git a/Telegram/SourceFiles/settings/settings_common.h b/Telegram/SourceFiles/settings/settings_common.h index c3692797806d75..d3492b96f3d7fc 100644 --- a/Telegram/SourceFiles/settings/settings_common.h +++ b/Telegram/SourceFiles/settings/settings_common.h @@ -214,6 +214,7 @@ struct SliderWithLabel { const style::MediaSlider &sliderSt, const style::FlatLabel &labelSt, int skip, - int minLabelWidth = 0); + int minLabelWidth = 0, + bool ignoreWheel = false); } // namespace Settings diff --git a/Telegram/SourceFiles/settings/settings_main.cpp b/Telegram/SourceFiles/settings/settings_main.cpp index 402b341596ff47..19c6ac654728b2 100644 --- a/Telegram/SourceFiles/settings/settings_main.cpp +++ b/Telegram/SourceFiles/settings/settings_main.cpp @@ -598,7 +598,8 @@ void SetupInterfaceScale( st::settingsScale, st::settingsScaleLabel, st::normalFont->spacew * 2, - st::settingsScaleLabel.style.font->width("300%")); + st::settingsScaleLabel.style.font->width("300%"), + true); container->add( std::move(sliderWithLabel.widget), icon ? st::settingsScalePadding : st::settingsBigScalePadding); diff --git a/Telegram/SourceFiles/ui/widgets/continuous_sliders.h b/Telegram/SourceFiles/ui/widgets/continuous_sliders.h index e5900bcbf22138..97839b4b1c3abe 100644 --- a/Telegram/SourceFiles/ui/widgets/continuous_sliders.h +++ b/Telegram/SourceFiles/ui/widgets/continuous_sliders.h @@ -230,4 +230,15 @@ class MediaSlider : public ContinuousSlider { }; +class MediaSliderWheelless : public MediaSlider { +public: + using Ui::MediaSlider::MediaSlider; + +protected: + void wheelEvent(QWheelEvent *e) override { + e->ignore(); + } + +}; + } // namespace Ui From acd40cbeb669bff8e49dcca7b395b6c721771a0f Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 4 Sep 2024 18:32:48 +0400 Subject: [PATCH 38/41] Apply invert_media flag on message send finish. --- Telegram/SourceFiles/history/history_item.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 004720dfd55e1e..3a9b5530645491 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1847,6 +1847,12 @@ void HistoryItem::applyEdition( } void HistoryItem::applySentMessage(const MTPDmessage &data) { + if (data.is_invert_media()) { + _flags |= MessageFlag::InvertMedia; + } else { + _flags &= ~MessageFlag::InvertMedia; + } + updateSentContent({ qs(data.vmessage()), Api::EntitiesFromMTP( From b20e2c37c14a62cd04951e2b60d2e6f879a99ba4 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 17:00:31 +0300 Subject: [PATCH 39/41] Fixed build on Qt6. --- Telegram/SourceFiles/history/history_view_swipe.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/history/history_view_swipe.cpp b/Telegram/SourceFiles/history/history_view_swipe.cpp index b028f696928804..b7a95517cedf92 100644 --- a/Telegram/SourceFiles/history/history_view_swipe.cpp +++ b/Telegram/SourceFiles/history/history_view_swipe.cpp @@ -230,7 +230,7 @@ void SetupSwipeHandler( processEnd(); } else { updateWith({ - .globalCursor = w->globalPos(), + .globalCursor = w->globalPosition().toPoint(), .position = QPointF(), .delta = state->delta - Ui::ScrollDelta(w), .touch = false, From a60385fc3db285ccb7d00f64a7ce148346818b8e Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 17:18:53 +0300 Subject: [PATCH 40/41] Removed QGraphicsOpacityEffect usage from media view overlay widget. --- .../media/view/media_view_overlay_widget.cpp | 85 ++++++++++++++++--- .../media/view/media_view_overlay_widget.h | 6 +- 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 90374064e67d73..9578cf50b90aa2 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -34,6 +34,7 @@ For license and copyright information please follow this link: #include "ui/text/format_values.h" #include "ui/item_text_options.h" #include "ui/painter.h" +#include "ui/rect.h" #include "ui/power_saving.h" #include "ui/cached_round_corners.h" #include "ui/gl/gl_window.h" @@ -100,7 +101,6 @@ For license and copyright information please follow this link: #include #include #include -#include #include @@ -228,6 +228,73 @@ QWidget *PipDelegate::pipParentWidget() { } // namespace +class OverlayWidget::SponsoredButton : public Ui::RippleButton { +public: + SponsoredButton(QWidget *parent) + : Ui::RippleButton(parent, st::mediaviewSponsoredButton.ripple) { + } + + void setText(QString text) { + _text = Ui::Text::String( + st::mediaviewSponsoredButton.style, + std::move(text), + kDefaultTextOptions, + width()); + resize(width(), _text.minHeight() * 2); + } + void setOpacity(float opacity) { + _opacity = opacity; + } + +protected: + void paintEvent(QPaintEvent *e) override { + auto p = QPainter(this); + const auto &st = st::mediaviewSponsoredButton; + + p.setOpacity(_opacity); + + const auto over = Ui::AbstractButton::isOver(); + const auto down = Ui::AbstractButton::isDown(); + { + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush((over || down) ? st.textBgOver : st.textBg); + p.drawRoundedRect( + rect(), + st::mediaviewCaptionRadius, + st::mediaviewCaptionRadius); + } + + Ui::RippleButton::paintRipple(p, 0, 0); + + p.setPen(st.textFg); + p.setBrush(Qt::NoBrush); + _text.draw(p, { + .position = QPoint( + (width() - _text.maxWidth()) / 2, + (height() - _text.minHeight()) / 2), + .outerWidth = width(), + .availableWidth = width(), + }); + } + + QImage prepareRippleMask() const override { + return Ui::RippleAnimation::RoundRectMask( + size(), + st::mediaviewCaptionRadius); + } + QPoint prepareRippleStartPosition() const override { + return mapFromGlobal(QCursor::pos()) + - rect::m::pos::tl(st::mediaviewSponsoredButton.padding); + } + +private: + Ui::Text::String _text; + float64 _opacity = 1.; + +}; + + struct OverlayWidget::SharedMedia { SharedMedia(SharedMediaKey key) : key(key) { } @@ -1812,9 +1879,9 @@ bool OverlayWidget::updateControlsAnimation(crl::time now) { } else { _controlsOpacity.update(dt, anim::linear); } - if (_sponsoredButtonOpacity && _sponsoredButton) { + if (_sponsoredButton) { const auto value = _controlsOpacity.current(); - _sponsoredButtonOpacity->setOpacity(value); + _sponsoredButton->setOpacity(value); _sponsoredButton->setAttribute( Qt::WA_TransparentForMouseEvents, value < 1); @@ -3678,19 +3745,14 @@ void OverlayWidget::initSponsoredButton() { } const auto &component = _session->sponsoredMessages(); const auto details = component.lookupDetails(_message->fullId()); - _sponsoredButton = base::make_unique_q( - _body, - rpl::single(details.buttonText), - st::mediaviewSponsoredButton); + _sponsoredButton = base::make_unique_q(_body); + _sponsoredButton->setText(details.buttonText); + _sponsoredButton->setOpacity(1.0); _sponsoredButton->setClickedCallback([=, link = details.link] { UrlClickHandler::Open(link); hide(); }); - _sponsoredButtonOpacity = base::make_unique_q( - _sponsoredButton.get()); - _sponsoredButtonOpacity->setOpacity(1.0); - _sponsoredButton->setGraphicsEffect(_sponsoredButtonOpacity.get()); } void OverlayWidget::updateThemePreviewGeometry() { @@ -6299,7 +6361,6 @@ void OverlayWidget::clearBeforeHide() { _helper->setControlsOpacity(1.); _groupThumbs = nullptr; _groupThumbsRect = QRect(); - _sponsoredButtonOpacity = nullptr; _sponsoredButton = nullptr; } diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 37c0da390b37f2..5114b169c7d1e4 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -20,8 +20,6 @@ For license and copyright information please follow this link: #include "media/view/media_view_open_common.h" #include "media/stories/media_stories_delegate.h" -class QGraphicsOpacityEffect; - class History; namespace anim { @@ -143,6 +141,7 @@ class OverlayWidget final class Renderer; class RendererSW; class RendererGL; + class SponsoredButton; // If changing, see paintControls()! enum class Over { @@ -700,8 +699,7 @@ class OverlayWidget final object_ptr _dropdown; base::Timer _dropdownShowTimer; - base::unique_qptr _sponsoredButton; - base::unique_qptr _sponsoredButtonOpacity; + base::unique_qptr _sponsoredButton; bool _receiveMouse = true; bool _processingKeyPress = false; From 5024f1db8c142a579b5bad5d6abf05ba583d1a32 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 4 Sep 2024 18:37:50 +0400 Subject: [PATCH 41/41] Beta version 5.4.6. - Add Swipe-To-Reply for modern touchpads and touchscreens. - Add text selection in collapsed and expanded blockquotes. - Fix text rendering in 100% interface scale 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 | 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 d16c8a6213f8cc..4234124d2b8a8c 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -10,7 +10,7 @@ + Version="5.4.6.0" /> Telegram Desktop Telegram Messenger LLP diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 00655ac818a8ac..81bc33e01bc0ae 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 5,4,5,0 - PRODUCTVERSION 5,4,5,0 + FILEVERSION 5,4,6,0 + PRODUCTVERSION 5,4,6,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -62,10 +62,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop" - VALUE "FileVersion", "5.4.5.0" + VALUE "FileVersion", "5.4.6.0" VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "5.4.5.0" + VALUE "ProductVersion", "5.4.6.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 8b4a34df9ba08c..edcb595699ab65 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 5,4,5,0 - PRODUCTVERSION 5,4,5,0 + FILEVERSION 5,4,6,0 + PRODUCTVERSION 5,4,6,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -53,10 +53,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram FZ-LLC" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "5.4.5.0" + VALUE "FileVersion", "5.4.6.0" VALUE "LegalCopyright", "Copyright (C) 2014-2024" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "5.4.5.0" + VALUE "ProductVersion", "5.4.6.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index dcfbe5709c6862..5c38f9e73b3918 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 = 5004005; -constexpr auto AppVersionStr = "5.4.5"; +constexpr auto AppVersion = 5004006; +constexpr auto AppVersionStr = "5.4.6"; constexpr auto AppBetaVersion = true; constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION; diff --git a/Telegram/build/version b/Telegram/build/version index 26daa6297a8587..d72fa2cd08e9e5 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,7 +1,7 @@ -AppVersion 5004005 +AppVersion 5004006 AppVersionStrMajor 5.4 -AppVersionStrSmall 5.4.5 -AppVersionStr 5.4.5 +AppVersionStrSmall 5.4.6 +AppVersionStr 5.4.6 BetaChannel 1 AlphaVersion 0 -AppVersionOriginal 5.4.5.beta +AppVersionOriginal 5.4.6.beta diff --git a/changelog.txt b/changelog.txt index 997b6689d917f2..b2c639b5514599 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,9 @@ +5.4.6 beta (04.09.24) + +- Add Swipe-To-Reply for modern touchpads and touchscreens. +- Add text selection in collapsed and expanded blockquotes. +- Fix text rendering in 100% interface scale on Windows. + 5.4.5 beta (31.08.24) - Fix possible crash in text rendering.