From ba363285a76fd0fc757f526da6b666a84e671586 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 1 Nov 2025 15:53:58 +0300 Subject: [PATCH] Added ability to add newly joined chat to folder. --- .../animations/toast/chats_filter_in.tgs | Bin 0 -> 4674 bytes Telegram/Resources/langs/lang.strings | 3 + .../Resources/qrc/telegram/animations.qrc | 1 + .../chat_helpers/chat_helpers.style | 23 ++++ .../history_view_self_forwards_tagger.cpp | 103 ++++++++++++++++++ .../view/history_view_self_forwards_tagger.h | 4 + 6 files changed, 134 insertions(+) create mode 100644 Telegram/Resources/animations/toast/chats_filter_in.tgs diff --git a/Telegram/Resources/animations/toast/chats_filter_in.tgs b/Telegram/Resources/animations/toast/chats_filter_in.tgs new file mode 100644 index 0000000000000000000000000000000000000000..aba04090d0b62de97d445cf0b17a9a24bd28ee5a GIT binary patch literal 4674 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 E0O3UVMF0Q* literal 0 HcmV?d00001 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index c2175c4c81..ac4778e273 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4580,6 +4580,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_message_tagged_with" = "Message tagged with {emoji}"; "lng_tagged_view_saved" = "View"; +"lng_add_channel_to_filter_selector" = "You can add a channel to your folder"; +"lng_add_group_to_filter_selector" = "You can add a group to your folder"; + "lng_context_animated_emoji" = "This message contains emoji from **{name} pack**."; "lng_context_animated_emoji_many#one" = "This message contains emoji from **{count} pack**."; "lng_context_animated_emoji_many#other" = "This message contains emoji from **{count} packs**."; diff --git a/Telegram/Resources/qrc/telegram/animations.qrc b/Telegram/Resources/qrc/telegram/animations.qrc index 7c598d0da1..632d39986b 100644 --- a/Telegram/Resources/qrc/telegram/animations.qrc +++ b/Telegram/Resources/qrc/telegram/animations.qrc @@ -46,6 +46,7 @@ ../../animations/toast/saved_messages.tgs ../../animations/toast/tagged.tgs ../../animations/my_gifts_empty.tgs + ../../animations/toast/chats_filter_in.tgs ../../animations/profile/profile_muting.tgs ../../animations/profile/profile_unmuting.tgs diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index ba4a07b5a6..d3c2ed199c 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -824,6 +824,29 @@ selfForwardsTaggerToast: Toast(defaultToast) { padding: margins(54px, 12px, 19px, 12px); iconPosition: point(15px, 6px); } +joinChatAddToFilterToast: Toast(defaultToast) { + minWidth: 160px; + maxWidth: 380px; + radius: 9px; + padding: margins(54px, 12px, 44px, 12px); + iconPosition: point(15px, 6px); +} +joinChatAddToFilterToastButton: IconButton(defaultIconButton) { + width: 40px; + height: 40px; + + icon: icon{ + { "chat/reactions_round_small", windowBgRipple }, + { "chat/reactions_expand_panel", windowSubTextFg }, + }; + iconOver: icon{ + { "chat/reactions_round_small", windowBgRipple }, + { "chat/reactions_expand_panel", windowSubTextFg }, + }; + rippleAreaPosition: point(10px, 10px); + rippleAreaSize: 20px; + ripple: universalRippleAnimation; +} choosePeerGroupIcon: icon {{ "info/edit/create_group", lightButtonFg }}; choosePeerChannelIcon: icon {{ "info/edit/create_channel", lightButtonFg }}; diff --git a/Telegram/SourceFiles/history/view/history_view_self_forwards_tagger.cpp b/Telegram/SourceFiles/history/view/history_view_self_forwards_tagger.cpp index 15ecec7479..82f008a0b8 100644 --- a/Telegram/SourceFiles/history/view/history_view_self_forwards_tagger.cpp +++ b/Telegram/SourceFiles/history/view/history_view_self_forwards_tagger.cpp @@ -10,8 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/call_delayed.h" #include "base/event_filter.h" #include "base/timer_rpl.h" +#include "boxes/choose_filter_box.h" #include "chat_helpers/share_message_phrase_factory.h" #include "core/ui_integration.h" +#include "data/data_chat_filters.h" #include "data/data_session.h" #include "data/data_user.h" #include "data/stickers/data_custom_emoji.h" @@ -27,10 +29,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/toast/toast_widget.h" #include "ui/toast/toast.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/popup_menu.h" #include "ui/widgets/tooltip.h" #include "window/window_session_controller.h" #include "styles/style_chat.h" #include "styles/style_chat_helpers.h" +#include "styles/style_info.h" namespace HistoryView { namespace { @@ -65,6 +69,20 @@ void SelfForwardsTagger::setup() { } showSelectorForMessages(data.ids); }, _lifetime); + _controller->session().data().recentJoinChat( + ) | rpl::start_with_next([=](const Data::RecentJoinChat &data) { + if (!_controller->session().data().chatsFilters().has()) { + return; + } + const auto history = _history ? _history() : nullptr; + if (!history || history->peer->id != data.fromPeerId) { + return; + } + const auto peerId = data.joinedPeerId; + if (const auto peer = _controller->session().data().peer(peerId)) { + showChannelFilterToast(peer); + } + }, _lifetime); } void SelfForwardsTagger::showSelectorForMessages( @@ -336,6 +354,91 @@ void SelfForwardsTagger::showTaggedToast(DocumentId reaction) { } } +void SelfForwardsTagger::showChannelFilterToast(not_null peer) { + hideToast(); + const auto toastText = peer->isChannel() && !peer->isMegagroup() + ? tr::lng_add_channel_to_filter_selector(tr::now) + : tr::lng_add_group_to_filter_selector(tr::now); + _toast = Ui::Toast::Show(_scroll, Ui::Toast::Config{ + .text = { .text = toastText }, + .st = &st::joinChatAddToFilterToast, + .attach = RectPart::Top, + .acceptinput = true, + .infinite = true, + }); + if (const auto strong = _toast.get()) { + const auto widget = strong->widget(); + createLottieIcon(widget, u"toast/chats_filter_in"_q); + const auto rightButton = createRightButton(widget); + const auto history = peer->owner().history(peer); + + struct State { + rpl::lifetime timerLifetime; + bool menuExpanded = false; + }; + const auto state = widget->lifetime().make_state(); + const auto restartTimer = [=](crl::time ms) { + state->timerLifetime.destroy(); + base::timer_once(ms) | rpl::start_with_next([=] { + hideToast(); + }, state->timerLifetime); + }; + + rightButton->setClickedCallback([=] { + state->menuExpanded = true; + state->timerLifetime.destroy(); + const auto menu = Ui::CreateChild( + rightButton, + st::foldersMenu); + menu->setForcedOrigin(Ui::PanelAnimation::Origin::TopRight); + FillChooseFilterMenu(_controller, menu, history); + if (!menu->empty()) { + menu->popup( + rightButton->mapToGlobal( + QPoint( + rightButton->width(), + rightButton->height() + rightButton->y()))); + QObject::connect(menu, &QObject::destroyed, [=] { + hideToast(); + }); + } else { + hideToast(); + } + }); + + base::install_event_filter(widget, [=](not_null event) { + if (event->type() == QEvent::MouseButtonPress) { + state->timerLifetime.destroy(); + return base::EventFilterResult::Continue; + } else if (!state->menuExpanded && event->type() == QEvent::Enter) { + state->timerLifetime.destroy(); + return base::EventFilterResult::Continue; + } else if (!state->menuExpanded && event->type() == QEvent::Leave) { + restartTimer(kTimerOnLeave); + return base::EventFilterResult::Continue; + } + return base::EventFilterResult::Continue; + }, widget->lifetime()); + + restartTimer(kInitTimer); + } +} + +not_null SelfForwardsTagger::createRightButton( + not_null widget) { + const auto button = Ui::CreateChild( + widget.get(), + st::joinChatAddToFilterToastButton); + widget->sizeValue() | rpl::start_with_next([=](const QSize &size) { + button->moveToRight( + st::lineWidth * 4, + (size.height() - button->height()) / 2); + }, button->lifetime()); + + button->show(); + return button; +} + void SelfForwardsTagger::hideToast() { if (const auto strong = _toast.get()) { strong->hideAnimated(); diff --git a/Telegram/SourceFiles/history/view/history_view_self_forwards_tagger.h b/Telegram/SourceFiles/history/view/history_view_self_forwards_tagger.h index df340472dc..53e5ca4e1f 100644 --- a/Telegram/SourceFiles/history/view/history_view_self_forwards_tagger.h +++ b/Telegram/SourceFiles/history/view/history_view_self_forwards_tagger.h @@ -29,6 +29,7 @@ class SessionController; namespace Ui { class RpWidget; +class AbstractButton; } // namespace Ui namespace Ui::Toast { @@ -57,7 +58,10 @@ private: void showSelectorForMessages(const MessageIdsList &ids); void showToast(const TextWithEntities &text, Fn callback); void showTaggedToast(DocumentId); + void showChannelFilterToast(not_null peer); void createLottieIcon(not_null widget, const QString &name); + not_null createRightButton( + not_null widget); void hideToast(); [[nodiscard]] QRect toastGeometry() const;