From d224b3d3011134c6feaca7fc56932622822b1369 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 5 Apr 2022 23:51:42 +0300 Subject: [PATCH] Added quick actions for folders to menu from chats list. --- Telegram/CMakeLists.txt | 2 + Telegram/Resources/langs/lang.strings | 3 + .../SourceFiles/boxes/choose_filter_box.cpp | 184 ++++++++++++++++++ .../SourceFiles/boxes/choose_filter_box.h | 33 ++++ .../SourceFiles/window/window_peer_menu.cpp | 31 ++- 5 files changed, 249 insertions(+), 4 deletions(-) create mode 100644 Telegram/SourceFiles/boxes/choose_filter_box.cpp create mode 100644 Telegram/SourceFiles/boxes/choose_filter_box.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 4db166fed8..a24daa0d37 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -216,6 +216,8 @@ PRIVATE boxes/background_preview_box.h boxes/change_phone_box.cpp boxes/change_phone_box.h + boxes/choose_filter_box.cpp + boxes/choose_filter_box.h boxes/connection_box.cpp boxes/connection_box.h boxes/create_poll_box.cpp diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index ed9be41dc7..8e05e06fab 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3082,6 +3082,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_filters_context_remove" = "Remove"; "lng_filters_remove_sure" = "This will remove the folder, your chats will not be deleted."; "lng_filters_remove_yes" = "Remove"; +"lng_filters_menu_add" = "Add to folder"; +"lng_filters_menu_remove" = "Remove from folder"; +"lng_filters_add_box_title" = "Add to..."; "lng_chat_theme_change" = "Change colors"; "lng_chat_theme_none" = "No\nTheme"; diff --git a/Telegram/SourceFiles/boxes/choose_filter_box.cpp b/Telegram/SourceFiles/boxes/choose_filter_box.cpp new file mode 100644 index 0000000000..c38b34e80a --- /dev/null +++ b/Telegram/SourceFiles/boxes/choose_filter_box.cpp @@ -0,0 +1,184 @@ +/* +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 "boxes/choose_filter_box.h" + +#include "apiwrap.h" +#include "data/data_chat_filters.h" +#include "data/data_session.h" +#include "history/history.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "ui/filter_icons.h" +#include "ui/layers/generic_box.h" +#include "ui/widgets/buttons.h" +#include "styles/style_settings.h" +#include "styles/style_payments.h" // paymentsSectionButton + +namespace { + +class FolderButton : public Ui::SettingsButton { +public: + FolderButton( + not_null parent, + const Data::ChatFilter &filter); + +protected: + void paintEvent(QPaintEvent *e) override; + +private: + const Ui::FilterIcon _icon; + +}; + +FolderButton::FolderButton( + not_null parent, + const Data::ChatFilter &filter) +: SettingsButton( + parent, + rpl::single(filter.title()), + st::paymentsSectionButton) +, _icon(Ui::ComputeFilterIcon(filter)) { +} + +void FolderButton::paintEvent(QPaintEvent *e) { + SettingsButton::paintEvent(e); + + Painter p(this); + const auto over = isOver() || isDown(); + const auto icon = Ui::LookupFilterIcon(_icon).normal; + icon->paint( + p, + st::settingsFilterIconLeft, + (height() - icon->height()) / 2, + width(), + (over + ? st::dialogsUnreadBgMutedOver + : st::dialogsUnreadBgMuted)->c); +} + +Data::ChatFilter ChangedFilter( + const Data::ChatFilter &filter, + not_null history, + bool add) { + auto always = base::duplicate(filter.always()); + if (add) { + always.insert(history); + } else { + always.remove(history); + } + auto never = base::duplicate(filter.never()); + if (add) { + never.remove(history); + } else { + never.insert(history); + } + return Data::ChatFilter( + filter.id(), + filter.title(), + filter.iconEmoji(), + filter.flags(), + std::move(always), + filter.pinned(), + std::move(never)); +} + +void ChangeFilterById( + FilterId filterId, + not_null history, + bool add) { + const auto list = history->owner().chatsFilters().list(); + const auto i = ranges::find(list, filterId, &Data::ChatFilter::id); + if (i != end(list)) { + const auto was = *i; + const auto filter = ChangedFilter(was, history, add); + history->owner().chatsFilters().set(filter); + history->session().api().request(MTPmessages_UpdateDialogFilter( + MTP_flags(MTPmessages_UpdateDialogFilter::Flag::f_filter), + MTP_int(filter.id()), + filter.tl() + )).fail([=](const MTP::Error &error) { + // Revert filter on fail. + history->owner().chatsFilters().set(was); + }).send(); + } +} + +} // namespace + +ChooseFilterValidator::ChooseFilterValidator(not_null history) +: _history(history) { +} + +bool ChooseFilterValidator::canAdd() const { + for (const auto &filter : _history->owner().chatsFilters().list()) { + if (!filter.contains(_history)) { + return true; + } + } + return false; +} + +bool ChooseFilterValidator::canRemove(FilterId filterId) const { + const auto list = _history->owner().chatsFilters().list(); + const auto i = ranges::find(list, filterId, &Data::ChatFilter::id); + if (i != end(list)) { + const auto &filter = *i; + return filter.contains(_history) + && ((filter.always().size() > 1) || filter.flags()); + } + return false; +} + +void ChooseFilterValidator::add(FilterId filterId) const { + ChangeFilterById(filterId, _history, true); +} + +void ChooseFilterValidator::remove(FilterId filterId) const { + ChangeFilterById(filterId, _history, false); +} + +void ChooseFilterBox( + not_null box, + not_null history) { + box->setTitle(tr::lng_filters_add_box_title()); + + const auto validator = ChooseFilterValidator(history); + + const auto container = box->verticalLayout()->add( + object_ptr(box->verticalLayout())); + + const auto rebuild = [=] { + while (container->count()) { + delete container->widgetAt(0); + } + for (const auto &filter : history->owner().chatsFilters().list()) { + if (filter.contains(history)) { + continue; + } + container->add( + object_ptr(box, filter), + style::margins() + )->setClickedCallback([=, id = filter.id()] { + validator.add(id); + box->closeBox(); + }); + } + container->resizeToWidth(box->verticalLayout()->width()); + if (!container->count()) { + box->closeBox(); + } + }; + + history->owner().chatsFilters().changed( + ) | rpl::start_with_next([=] { + rebuild(); + }, box->lifetime()); + rebuild(); + + box->addButton(tr::lng_close(), [=] { box->closeBox(); }); +} diff --git a/Telegram/SourceFiles/boxes/choose_filter_box.h b/Telegram/SourceFiles/boxes/choose_filter_box.h new file mode 100644 index 0000000000..33404bc032 --- /dev/null +++ b/Telegram/SourceFiles/boxes/choose_filter_box.h @@ -0,0 +1,33 @@ +/* +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 GenericBox; +} // namespace Ui + +class History; + +class ChooseFilterValidator final { +public: + ChooseFilterValidator(not_null history); + + [[nodiscard]] bool canAdd() const; + [[nodiscard]] bool canRemove(FilterId filterId) const; + + void add(FilterId filterId) const; + void remove(FilterId filterId) const; + +private: + const not_null _history; + +}; + +void ChooseFilterBox( + not_null box, + not_null history); diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index f2b0e043e2..597271ee25 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/max_invite_box.h" #include "boxes/mute_settings_box.h" #include "boxes/add_contact_box.h" +#include "boxes/choose_filter_box.h" #include "boxes/create_poll_box.h" #include "boxes/pin_messages_box.h" #include "boxes/peers/add_bot_to_chat_box.h" @@ -180,7 +181,7 @@ private: void addToggleMuteSubmenu(bool addSeparator); void addSupportInfo(); void addInfo(); - //void addToFolder(); + void addToggleFolder(); void addToggleUnreadMark(); void addToggleArchive(); void addClearHistory(); @@ -425,8 +426,30 @@ void Filler::addInfo() { }, peer->isUser() ? &st::menuIconProfile : &st::menuIconInfo); } -//void Filler::addToFolder() { -//} +void Filler::addToggleFolder() { + const auto history = _request.key.history(); + if (!history) { + return; + } + if (!_request.filterId) { + if (!ChooseFilterValidator(history).canAdd()) { + return; + } + const auto window = _controller; + _addAction(tr::lng_filters_menu_add(tr::now), [=] { + window->show(Box(ChooseFilterBox, history)); + }, nullptr); + } else { + const auto id = _request.filterId; + const auto validator = ChooseFilterValidator(history); + if (!validator.canRemove(id)) { + return; + } + _addAction(tr::lng_filters_menu_remove(tr::now), [=] { + validator.remove(id); + }, nullptr); + } +} void Filler::addToggleUnreadMark() { const auto peer = _peer; @@ -817,7 +840,7 @@ void Filler::fillChatsListActions() { } addToggleMuteSubmenu(false); addToggleUnreadMark(); - // addToFolder(); + addToggleFolder(); if (const auto user = _peer->asUser()) { if (!user->isContact()) { addBlockUser();