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 0000000000..aba04090d0 Binary files /dev/null and b/Telegram/Resources/animations/toast/chats_filter_in.tgs differ 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;