From 2be76760de1adccbf827d68df759d349575f16aa Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 21 Mar 2025 21:01:31 +0300 Subject: [PATCH] Slightly improved style of settings for quick dialog action. --- Telegram/Resources/langs/lang.strings | 2 + .../dialogs/dialogs_quick_action.cpp | 26 ++- .../dialogs/dialogs_quick_action.h | 4 +- Telegram/SourceFiles/settings/settings.style | 2 + .../SourceFiles/settings/settings_chat.cpp | 177 +++++++++++++++++- 5 files changed, 199 insertions(+), 12 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index f21eeed320..dae3297d30 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1182,6 +1182,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_quick_dialog_action_title" = "Chat list quick action"; "lng_settings_quick_dialog_action_about" = "Choose the action you want to perform when you middle-click or swipe left in the chat list."; +"lng_settings_quick_dialog_action_both" = "Swipe left and Middle-click"; +"lng_settings_quick_dialog_action_swipe" = "Swipe left"; "lng_settings_quick_dialog_action_mute" = "Mute"; "lng_settings_quick_dialog_action_unmute" = "Unmute"; "lng_settings_quick_dialog_action_pin" = "Pin"; diff --git a/Telegram/SourceFiles/dialogs/dialogs_quick_action.cpp b/Telegram/SourceFiles/dialogs/dialogs_quick_action.cpp index 8e546b0d30..340a9f3b6e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_quick_action.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_quick_action.cpp @@ -213,8 +213,10 @@ void DrawQuickAction( QPainter &p, const QRect &rect, not_null icon, - Ui::QuickDialogActionLabel label) { - const auto iconSize = st::dialogsQuickActionSize; + Ui::QuickDialogActionLabel label, + float64 iconRatio, + bool twoLines) { + const auto iconSize = st::dialogsQuickActionSize * iconRatio; const auto innerHeight = iconSize * 2; const auto top = (rect.height() - innerHeight) / 2; icon->paint(p, rect.x() + (rect.width() - iconSize) / 2, top); @@ -222,10 +224,22 @@ void DrawQuickAction( p.setBrush(Qt::NoBrush); const auto availableWidth = rect.width(); p.setFont(SwipeActionFont(label, availableWidth)); - p.drawText( - QRect(rect.x(), top, availableWidth, innerHeight), - ResolveQuickDialogLabel(label), - style::al_bottom); + if (twoLines) { + auto text = ResolveQuickDialogLabel(label); + const auto index = text.indexOf(' '); + if (index != -1) { + text = text.replace(index, 1, '\n'); + } + p.drawText( + QRect(rect.x(), top, availableWidth, innerHeight), + std::move(text), + style::al_bottom); + } else { + p.drawText( + QRect(rect.x(), top, availableWidth, innerHeight), + ResolveQuickDialogLabel(label), + style::al_bottom); + } } } // namespace Dialogs diff --git a/Telegram/SourceFiles/dialogs/dialogs_quick_action.h b/Telegram/SourceFiles/dialogs/dialogs_quick_action.h index e8d53c06b7..4ba26f291d 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_quick_action.h +++ b/Telegram/SourceFiles/dialogs/dialogs_quick_action.h @@ -50,6 +50,8 @@ void DrawQuickAction( QPainter &p, const QRect &rect, not_null icon, - Ui::QuickDialogActionLabel label); + Ui::QuickDialogActionLabel label, + float64 iconRatio = 1., + bool twoLines = false); } // namespace Dialogs diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index a64cc6e92a..b866ec905a 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -682,3 +682,5 @@ settingsChatLinkField: InputField(defaultInputField) { style: defaultTextStyle; } + +settingsQuickDialogActionsTriggerFont: font(11px); diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index 89399c0370..d375700ee1 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -23,6 +23,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/background_preview_box.h" #include "boxes/download_path_box.h" #include "boxes/local_storage_box.h" +#include "dialogs/ui/dialogs_quick_action_context.h" +#include "dialogs/dialogs_quick_action.h" #include "ui/boxes/choose_font_box.h" #include "ui/wrap/vertical_layout.h" #include "ui/wrap/slide_wrap.h" @@ -39,11 +41,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/toast/toast.h" #include "ui/image/image.h" #include "ui/painter.h" +#include "ui/rect.h" #include "ui/vertical_list.h" #include "ui/ui_utility.h" #include "ui/widgets/menu/menu_add_action_callback.h" #include "history/view/history_view_quick_action.h" #include "lang/lang_keys.h" +#include "lottie/lottie_icon.h" #include "export/export_manager.h" #include "window/themes/window_theme.h" #include "window/themes/window_themes_embedded.h" @@ -76,6 +80,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_layers.h" #include "styles/style_menu_icons.h" #include "styles/style_window.h" +#include "styles/style_dialogs.h" namespace Settings { namespace { @@ -1272,7 +1277,7 @@ void SetupChatBackground( }, adaptive->lifetime()); } -void SetupChatListSwipe( +void SetupChatListQuickAction( not_null controller, not_null container) { Ui::AddDivider(container); @@ -1282,13 +1287,141 @@ void SetupChatListSwipe( tr::lng_settings_quick_dialog_action_title()); using Type = Dialogs::Ui::QuickDialogAction; + using LabelType = Dialogs::Ui::QuickDialogActionLabel; const auto group = std::make_shared>( Core::App().settings().quickDialogAction()); group->setChangedCallback([=](Type value) { Core::App().settings().setQuickDialogAction(value); Core::App().saveSettings(); }); - container->add( + + const auto actionToLabel = [](Type value) { + switch (value) { + case Type::Mute: return LabelType::Mute; + case Type::Pin: return LabelType::Pin; + case Type::Read: return LabelType::Read; + case Type::Archive: return LabelType::Archive; + case Type::Delete: return LabelType::Delete; + default: return LabelType::Disabled; + } + }; + static constexpr auto kDisabledIconRatio = 1.25; + + const auto addPreview = [=](not_null container) { + const auto widget = container->add( + object_ptr(container)); + widget->resize(0, st::dialogsRowHeight); + struct State { + std::unique_ptr icon; + }; + const auto state = widget->lifetime().make_state(); + group->value() | rpl::start_with_next([=](Type value) { + const auto label = actionToLabel(value); + state->icon = Lottie::MakeIcon({ + .name = Dialogs::ResolveQuickDialogLottieIconName(label), + .sizeOverride = Size((label == LabelType::Disabled) + ? int(st::dialogsQuickActionSize * kDisabledIconRatio) + : st::dialogsQuickActionSize), + }); + state->icon->animate( + [=] { widget->update(); }, + 0, + state->icon->framesCount() - 1); + widget->update(); + }, widget->lifetime()); + widget->paintRequest() | rpl::start_with_next([=] { + auto p = QPainter(widget); + + const auto height = st::dialogsRowHeight; + const auto actionWidth = st::dialogsQuickActionRippleSize * 0.75; + const auto rightOffset = st::dialogsQuickActionRippleSize + + st::dialogsQuickActionSize; + const auto rect = QRect( + widget->width() + - actionWidth + - st::boxRowPadding.right() + - rightOffset, + 0, + actionWidth, + height); + + auto path = QPainterPath(); + path.addRoundedRect( + QRect( + -actionWidth, + 0, + rect::right(rect) + actionWidth, + height), + st::roundRadiusLarge, + st::roundRadiusLarge); + p.setClipPath(path); + + const auto label = actionToLabel(group->current()); + const auto isDisabled = (label == LabelType::Disabled); + + auto hq = PainterHighQualityEnabler(p); + p.fillRect( + QRect(0, 0, rect::right(rect), st::lineWidth), + st::windowBgOver); + p.fillRect( + QRect( + 0, + rect::bottom(rect) - st::lineWidth, + rect::right(rect), + st::lineWidth), + st::windowBgOver); + p.fillRect(rect, Dialogs::ResolveQuickActionBg(label)); + if (state->icon) { + Dialogs::DrawQuickAction( + p, + rect, + state->icon.get(), + label, + isDisabled ? kDisabledIconRatio : 1., + isDisabled); + } + p.translate(-height / 2, 0); + p.setPen(Qt::NoPen); + p.setBrush(st::windowBgOver); + p.drawEllipse(Rect(Size(height)) - Margins(height / 6)); + + const auto h = st::normalFont->ascent / 1.5; + p.drawRoundedRect( + height, + height / 2 - h * 1.5, + st::dialogsQuickActionRippleSize * 0.6, + h, + h / 2, + h / 2); + p.drawRoundedRect( + height, + height / 2 + h, + st::dialogsQuickActionRippleSize * 1.0, + h, + h / 2, + h / 2); + + p.setClipping(false); + p.resetTransform(); + p.setFont(st::settingsQuickDialogActionsTriggerFont); + p.setPen(st::windowSubTextFg); + p.drawText( + QRect( + widget->width() + - st::dialogsQuickActionRippleSize + - st::boxRowPadding.right(), + 0, + st::dialogsQuickActionRippleSize, + height), + isDisabled + ? tr::lng_settings_quick_dialog_action_swipe(tr::now) + : tr::lng_settings_quick_dialog_action_both(tr::now), + style::al_center); + }, widget->lifetime()); + }; + + const auto &st = st::settingsButton; + const auto button = container->add( object_ptr( container, group->value() | rpl::map([](Type value) { @@ -1302,8 +1435,39 @@ void SetupChatListSwipe( ? tr::lng_settings_quick_dialog_action_archive : tr::lng_settings_quick_dialog_action_disabled)(); }) | rpl::flatten_latest(), - st::settingsButtonNoIcon) - )->setClickedCallback([=] { + st)); + + { + const auto icon = button->lifetime().make_state(button); + icon->setAttribute(Qt::WA_TransparentForMouseEvents); + icon->resize(st::menuIconArchive.size()); + icon->show(); + button->sizeValue( + ) | rpl::start_with_next([=, left = st.iconLeft](QSize size) { + icon->moveToLeft( + left, + (size.height() - icon->height()) / 2, + size.width()); + }, icon->lifetime()); + icon->paintRequest( + ) | rpl::start_with_next([=] { + auto p = QPainter(icon); + const auto value = group->current(); + ((value == Dialogs::Ui::QuickDialogAction::Mute) + ? st::menuIconMute + : (value == Dialogs::Ui::QuickDialogAction::Pin) + ? st::menuIconPin + : (value == Dialogs::Ui::QuickDialogAction::Read) + ? st::menuIconMarkRead + : (value == Dialogs::Ui::QuickDialogAction::Delete) + ? st::menuIconDelete + : (value == Dialogs::Ui::QuickDialogAction::Archive) + ? st::menuIconArchive + : st::menuIconShowInFolder).paintInCenter(p, icon->rect()); + }, icon->lifetime()); + } + + button->setClickedCallback([=] { controller->uiShow()->showBox(Box([=](not_null box) { box->setTitle(tr::lng_settings_quick_dialog_action_title()); const auto addRadio = [&](Type value, tr::phrase<> phrase) { @@ -1316,6 +1480,9 @@ void SetupChatListSwipe( st::settingsSendType), st::settingsSendTypePadding); }; + addPreview(box->verticalLayout()); + Ui::AddSkip(box->verticalLayout()); + Ui::AddSkip(box->verticalLayout()); addRadio(Type::Mute, tr::lng_settings_quick_dialog_action_mute); addRadio(Type::Pin, tr::lng_settings_quick_dialog_action_pin); addRadio(Type::Read, tr::lng_settings_quick_dialog_action_read); @@ -1868,7 +2035,7 @@ void Chat::setupContent(not_null controller) { SetupThemeSettings(controller, content); SetupCloudThemes(controller, content); SetupChatBackground(controller, content); - SetupChatListSwipe(controller, content); + SetupChatListQuickAction(controller, content); SetupStickersEmoji(controller, content); SetupMessages(controller, content); Ui::AddDivider(content);